Index: /branches/features/grailsUpgrade/.classpath
===================================================================
--- /branches/features/grailsUpgrade/.classpath	(revision 875)
+++ /branches/features/grailsUpgrade/.classpath	(revision 875)
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+<classpathentry kind="src" path="src/java"/>
+<classpathentry kind="src" path="src/groovy"/>
+<classpathentry kind="src" path="grails-app/conf"/>
+<classpathentry kind="src" path="grails-app/controllers"/>
+<classpathentry kind="src" path="grails-app/domain"/>
+<classpathentry kind="src" path="grails-app/services"/>
+<classpathentry kind="src" path="grails-app/taglib"/>
+<classpathentry kind="src" path="test/integration"/>
+<classpathentry kind="src" path="test/unit"/>
+<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+<classpathentry kind="output" path="web-app/WEB-INF/classes"/>
+<classpathentry kind="var" path="GRAILS_HOME/ant/lib/ant.jar"/>
+<classpathentry kind="var" path="GRAILS_HOME/lib/slf4j-api-1.5.6.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jasper-runtime-5.5.15.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jsp-api-2.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/sitemesh-2.4.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-codec-1.3.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/oro-2.0.8.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/backport-util-concurrent-3.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-dbcp-1.2.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/start.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ant-junit-1.7.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ant-1.7.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/hsqldb-1.8.0.5.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jetty-plus-6.1.14.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/slf4j-log4j12-1.5.6.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/junit-3.8.2.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/spring-webmvc-2.5.6.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/org.springframework.webflow-2.0.3.RELEASE.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jstl-2.4.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ehcache-1.5.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/xpp3_min-1.1.3.4.O.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ivy-2.0.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jsp-api-2.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jetty-util-6.1.14.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jline-0.9.91.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jetty-naming-6.1.14.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ant-nodeps-1.7.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-collections-3.2.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/standard-2.4.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/spring-2.5.6.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jasper-compiler-jdt-5.5.15.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/log4j-1.2.15.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/groovy-all-1.6.3.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/svnkit-1.2.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jcl-over-slf4j-1.5.6.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jta-1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jetty-6.1.14.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/cglib-nodep-2.1_3.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/spring-test-2.5.6.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/standard-2.3.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-el-1.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/org.springframework.binding-2.0.3.RELEASE.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-validator-1.3.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/oscache-2.4.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/org.springframework.js-2.0.3.RELEASE.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/serializer.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ognl-2.6.9.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ant-trax.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ant-launcher-1.7.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jsr107cache-1.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-fileupload-1.2.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jstl-2.3.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/servlet-api-2.5-6.1.14.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/jasper-compiler-5.5.15.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-lang-2.4.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/ejb3-persistence-3.3.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-beanutils-1.7.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-io-1.4.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/gant_groovy1.6-1.6.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/antlr-2.7.6.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-cli-1.0.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/lib/commons-pool-1.2.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-test-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-scripts-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-bootstrap-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-gorm-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-resources-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-crud-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-webflow-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-core-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-spring-1.1.1.jar" />
+<classpathentry kind="var" path="GRAILS_HOME/dist/grails-web-1.1.1.jar" />
+</classpath>
Index: /branches/features/grailsUpgrade/.project
===================================================================
--- /branches/features/grailsUpgrade/.project	(revision 875)
+++ /branches/features/grailsUpgrade/.project	(revision 875)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>gnuMims</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.codehaus.groovy.eclipse.groovyBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.codehaus.groovy.eclipse.groovyNature</nature>
+	</natures>
+</projectDescription>
Index: /branches/features/grailsUpgrade/COPYING
===================================================================
--- /branches/features/grailsUpgrade/COPYING	(revision 875)
+++ /branches/features/grailsUpgrade/COPYING	(revision 875)
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 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 Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are 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.
+
+  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.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  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 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 work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero 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 your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  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 AGPL, see
+<http://www.gnu.org/licenses/>.
Index: /branches/features/grailsUpgrade/INSTALL
===================================================================
--- /branches/features/grailsUpgrade/INSTALL	(revision 875)
+++ /branches/features/grailsUpgrade/INSTALL	(revision 875)
@@ -0,0 +1,14 @@
+GnuMims is a web application built with the Grails (www.grails.org) web framework. 
+To run from source a working Grails installation is required.
+To run from WAR (web application archive) a working Java servlet (e.g: Tomcat) is required.
+
+To run from source:
+ - cd $projectdir
+ - grails run-app
+
+To run from war:
+ - select and configure database.
+ - deploy to Java application server as per server instructions.
+
+See www.gnumims.org for more.
+http://www.gnumims.org/trac/wiki/Installing
Index: /branches/features/grailsUpgrade/README
===================================================================
--- /branches/features/grailsUpgrade/README	(revision 875)
+++ /branches/features/grailsUpgrade/README	(revision 875)
@@ -0,0 +1,17 @@
+    GnuMims - A web application providing a Maintenance and Inventory Management Solution for your Assets.
+    Copyright (C) 2008-2010 Gavin Kromhout
+    Copyright (C) 2008-2010 Steven Tucker
+    Copyright (C) 2008-2010 Raymond Smith
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>
Index: /branches/features/grailsUpgrade/application.properties
===================================================================
--- /branches/features/grailsUpgrade/application.properties	(revision 875)
+++ /branches/features/grailsUpgrade/application.properties	(revision 875)
@@ -0,0 +1,19 @@
+#Grails Metadata file
+#Thu Jan 27 17:24:52 EST 2011
+app.grails.version=1.2.2
+app.name=gnuMims
+app.servlet.version=2.4
+app.vcsRevision=$Rev$
+app.version=
+plugins.acegi=0.5.2
+plugins.class-diagram=0.5.1
+plugins.export=0.6
+plugins.filterpane=0.6.8
+plugins.help-balloons=1.3
+plugins.hibernate=1.2.2
+plugins.jasper=0.9.7
+plugins.navigation=1.1.1
+plugins.quartz=0.4.2
+plugins.richui=0.8
+plugins.searchable=0.5.5
+plugins.tomcat=1.2.2
Index: /branches/features/grailsUpgrade/doc/DatabaseDesign.tex
===================================================================
--- /branches/features/grailsUpgrade/doc/DatabaseDesign.tex	(revision 875)
+++ /branches/features/grailsUpgrade/doc/DatabaseDesign.tex	(revision 875)
@@ -0,0 +1,65 @@
+\documentclass[12pt,a4paper]{article}
+\usepackage{inputenc}
+\usepackage{color}
+\usepackage{graphicx}
+\author{Gavin Kromhout and Steven Tucker}
+\title{GnuMims Database Design}
+\date{09 November 2008}
+%\date{\today{}}
+
+\begin{document}
+%Turn off section numbers
+\setcounter{secnumdepth}{-1}
+%Need this else header formatting vanishes.
+\maketitle {}
+
+
+\section{Intro}
+ Many organisations use a ``database''.
+ Maintenace departments often buy very expensive and customised software to monitor and improve their maintenace activities.
+ There are many advantages to using a database.
+ This is our attempt to create GnuMims, for open source Maintenace and Inventory Management.
+
+
+\section{Common requirements}
+\begin{itemize}
+ \item Easy install, must have a running demo within a few commands.
+  \subitem Scripted, packaged and/or web framework.
+ \item Open source, GNU GPL.
+  \subitem Leverage the best of open source for fast development
+  \subitem and ease of maintenance.
+ \item SVN and FTP/SSH for collaboration.
+ \item Grails web framework.
+  \item Architecture MVC
+%TODO:
+\textcolor{red}
+{
+ \item Specify naming convention for database and code.
+ \item Maintain Project Flowcharts, ERD, Database Schema, BLL and Documentation.
+  \subitem Use Dia, flowcharts, recall etc.
+}
+\end{itemize}
+
+\section{Project Management Flowchart}
+\begin{center}
+ \includegraphics[scale=0.75]{ProjectManagementFlowchart.png}
+\end{center}
+
+\section{Entity Relationship Diagram}
+\begin{center}
+ \includegraphics[scale=0.25]{gnuMimsErd.png}
+\end{center}
+
+\section{Core Scope}
+\textcolor{red}
+{
+Determine the core scope as per ERD.
+Determine the initial scope as per ERD.
+Indicate standalone packages.
+}
+
+\begin{center}
+The end.
+\end{center}
+
+\end{document}
Index: /branches/features/grailsUpgrade/doc/Definitions/EntryTerms.txt
===================================================================
--- /branches/features/grailsUpgrade/doc/Definitions/EntryTerms.txt	(revision 875)
+++ /branches/features/grailsUpgrade/doc/Definitions/EntryTerms.txt	(revision 875)
@@ -0,0 +1,45 @@
+Entry terms and definitions.
+
+Entry class attributes:
+
+    comment
+                - Default = required so nothing.
+                - Larger text area.
+                - What was done for this entry.
+
+    dateDone
+                - Default = now.
+                - Precision = day.
+                - Can be changed.
+                - Date that person is reporting as the date entry was done.
+
+    dateEntered
+                - Default = now.
+                - Precision = second.
+                - Cannot be changed.
+                - Date the entry was actually entered.
+
+    durationHour
+                - Default = 0.
+                - Integer representing hours spent on this entry.
+
+    durationMinute
+                - Default = 0 
+                - Integer representing minutes spent on this entry.
+
+    enteredBy
+                - Default = current person.
+                - Cannot be changed.
+                - Of Class Person.
+
+    task        
+                - The task this entry belongs to.
+                - Of Class Task.
+
+    entryType
+                - Default = one of "Work Done", "Fault", "Production Note", "Work Request".
+                - Default depends on where the entry comes from.
+                - Of Class EntryType.
+
+#Required actions.
+Return a list of all entries for a Task.
Index: /branches/features/grailsUpgrade/doc/Definitions/InventoryTerms.txt
===================================================================
--- /branches/features/grailsUpgrade/doc/Definitions/InventoryTerms.txt	(revision 875)
+++ /branches/features/grailsUpgrade/doc/Definitions/InventoryTerms.txt	(revision 875)
@@ -0,0 +1,87 @@
+Inventory terms and definitions.
+
+InventoryItem:
+    name
+                - Default = required so nothing.
+                - Standard length used most places.
+
+    description
+                - Default = "".     
+                - Longer for additional info only shown in detail views.
+
+    isActive    
+                - Default=true, false if "Trashed".
+                - Set false by Trash action.
+                - Set true by Restore action. 
+                - Require true when creating new entries/lists for dropdowns etc.
+                - Ignore when viewing old associations or creating lists for searching etc.
+
+    isObsolete    
+                - Default=false.
+                - Is this InventoryItem now considered obsolete by the manufacturer.
+
+    manufacturersPartNumber
+                - Default = "".     
+                - The part number that the manufacturer uses to identify this InventoryItem.
+
+    suppliersPartNumber
+                - Default = "".     
+                - The part number that the supplier uses to identify this InventoryItem.
+
+    enableReorder    
+                - Default=true.
+                - Should this InventoryItem appear on reorder and auto order lists.
+
+    reorderPoint
+                - Required so no default.
+                - Once total StoredItems equals this point the item will appear on reorder and auto order lists.
+
+    recommendedReorderPoint
+                - Provided the required information is available a recommendedReorderPoint is calculated.
+
+    averageDeliveryTime
+                - The average delivery time in days from placement of reorder.
+
+   inventoryGroup
+                - Default = required so nothing.
+                - The InventoryGroup this InventoryItem belongs to.
+                - Initially one of "Misc", "Mechanical", "Electrical", "Production", "Raw Materials".
+                - Of Class InventoryGroup.
+
+    inventoryType
+                - Default = required so nothing.
+                - Initially one of "Consumable", "Repairable".
+                - Of Class InventoryType.
+
+    unitOfMeasure
+                - Default = required so nothing.
+                - Initially one of "each", "meter(s)", "box(es)", "litre(s)"
+                - Of Class UnitOfMeasure.
+
+    alternateItems
+                - An InventoryItem may have many alternateItems of Class InventoryItem.
+                - Indicates that this InventoryItem has alternatives.
+
+    spareFor
+                - An InventoryItem may have many assets that it is a spare for, of Class Asset.
+
+    storedItems
+                - An InventoryItem may have many StoredItems of Class StoredItem.
+
+    inventoryMovements
+                - An InventoryItem may have many InventoryMovements of Class InventoryMovement.
+
+    manufacturers
+                - An InventoryItem may have many Manufacturers of the Class Manufacturer.
+
+    suppliers
+               - An InventoryItem may have many Suppliers of the Class Supplier.
+
+
+#External required actions.
+Calculate/Show total storedItems.
+
+InventoryMovementType
+    Initially one of "Used", "Received", "Repaired"
+
+
Index: /branches/features/grailsUpgrade/doc/Definitions/PreventativeMaintenance_PM.txt
===================================================================
--- /branches/features/grailsUpgrade/doc/Definitions/PreventativeMaintenance_PM.txt	(revision 875)
+++ /branches/features/grailsUpgrade/doc/Definitions/PreventativeMaintenance_PM.txt	(revision 875)
@@ -0,0 +1,17 @@
+Preventative Maintenance or PM
+
+ * A PM is simply a task where:
+  * Task type = "Preventative Maintenance"
+  * As with any task a PM may have a recurring schedule, procedure and entries etc.
+
+The following information can be automatically returned from the system.
+
+ * PM frequency = Task.taskRecurringSchedule
+
+ * PM KPI's:
+  * Total PM's = Task.findAllByTaskType("Preventative Maintenance")
+  * Complete PM's = Total.findAllByTaskStatus("Complete")
+  * PM completetion rate = Complete/Total
+  * Missed PM's = Total - Complete
+
+ * Find all Recurring PM tasks = context{TaskRecShed.task.taskType("Preventative Maintenance") and Date in range}
Index: /branches/features/grailsUpgrade/doc/Definitions/TaskActions.txt
===================================================================
--- /branches/features/grailsUpgrade/doc/Definitions/TaskActions.txt	(revision 875)
+++ /branches/features/grailsUpgrade/doc/Definitions/TaskActions.txt	(revision 875)
@@ -0,0 +1,45 @@
+Action          Modification (dates have precision='second')        Task (dates have precision='$day')
+------------------------------------------------------------------------------------------------------
+
+Create      ->  recordModification("Created")                       <-  is the date created.
+
+Schedule    ->  recordModification("SetTargetStartDate")            ->  set: Task.targetStartDate
+
+                recordModification("SetTargetCompletionDate")       ->  set: Task.targetCompletionDate
+
+Start       ->  recordModification("ActualStartDate")               <-  is the date started
+
+Complete    ->  recordModification("ActualCompletionDate")          <-  is the date completed   
+
+Reopen    ->  recordModification("ActualCompletionDate")          <-  is the date completed   
+                   
+Delete      ->  recordModification("Deleted")                       ->  Task.isActive = false
+Trash       ->  recordModification("Trashed")                       ->  Task.isActive = false
+                 
+Restore    ->  recordModification("Restore")                        ->  Task.isActive = true
+                
+Approve     ->  recordModification("Approve")                       ->  Task.isApproved = true
+                
+Renege      ->  recordModification("Renege")                        ->  Task.isApproved = false
+
+AddAssignedPerson->  recordModification("AddAssignedPerson", $assignedPerson)
+
+RmAssignedPerson ->  recordModification("RmAssignedPerson", $assignedPerson)
+
+recordModification(String type) {
+    Modification.modificationType = ModificationType.findByName(type)
+    Modification.date = now
+    Modification.person = userName                                     
+    Modification.comment = ""  
+}
+recordModification(String type, String comment) {
+    Modification.modificationType = ModificationType.findByName(type)
+    Modification.date = now
+    Modification.person = userName                                      
+    Modification.comment = comment  
+}                     
+
+
+Required Services:
+TaskCopy
+TaskGenerateSubTask                                      
Index: /branches/features/grailsUpgrade/doc/Definitions/TaskTerms.txt
===================================================================
--- /branches/features/grailsUpgrade/doc/Definitions/TaskTerms.txt	(revision 875)
+++ /branches/features/grailsUpgrade/doc/Definitions/TaskTerms.txt	(revision 875)
@@ -0,0 +1,137 @@
+Intro
+
+ * Tasks may have one parent task and many sub tasks.
+ * Tasks may have a recurring schedule.
+ * Tasks with an enabled recurring schedule automatically generate subTasks.
+ * Tasks may have many "work done" or "fault" entries.
+
+Task terms and definitions.
+
+Task:
+    description
+                - Default = required so nothing.
+                - Standard length used most places.
+
+    comment
+                - Default = "".     
+                - Longer for additional info only shown in detail views.
+
+    targetStartDate
+                - Default = now.
+                - The date we would like task to start.
+                - Set by Schedule action.
+                - Set to now for Unscheduled Breakin.
+
+    targetCompletionDate
+                - Default = now.
+                - The date we would like task to be completed by.
+                - Set by Schedule action.
+                - Set to now for Unscheduled Breakin.
+
+    isScheduled 
+                - Default = false.
+                - Set true by Schedule action.
+
+    isApproved  
+                - Default=false, true when approved.
+                - Set true by Approve action
+                - Set false by Renege action.
+
+    isActive    
+                - Default=true, false if "Deleted".
+                - Set false by Delete action.
+                - Set true by Undelete action. 
+                - Require true when creating new entries/lists for dropdowns etc.
+                - Ignore when viewing old associations or creating lists for searching etc.
+
+    taskGroup
+                - Default = required so nothing.
+                - The taskGroup this task belongs to.
+                - Of Class TaskGroup.
+
+    taskStatus
+                - Default = "Not Started".
+                - The current status of this task.
+                - Of Class TaskStatus.
+                - One of "Not Started", "In Progress" or "Completed".
+                - Automagically set to "In Progress" on first "Work Done" entry.
+                - Automagically set to "Completed" by action button.
+
+    taskPriority
+                - Default = Normal.
+                - Of Class TaskPriority.
+                - One of Normal, Low, High, Immediate.
+                - Automagically set to High if Unscheduled Breakin?
+                - Automagically set to ?
+
+    taskType
+                - Default = required so nothing.
+                - Of Class TaskType.
+                - Automagically set to ?
+
+    parentTask
+                - Default = not always used so nothing.
+                - Indicates that this is a subTask and links back to the parentTask.
+                - Of Class Task.
+
+    leadPerson  
+                - Default = current person.
+                - The primay contact person.
+                - Of Class Person.
+
+    primaryAsset  
+                - The primay asset that costs will be assigned to.
+                - Of Class Asset
+
+    entries       
+                - A task may have many entries of Class Entry.
+                - Persons other than the leadPerson or assingedPersons may create entries.
+    
+    modifications
+                - A task may have many modifications of Class Modification.
+
+    assignedPersons
+                - A task may have many assingedPersons of Class Person.
+                - estimatedHour and estimatedMinute.
+
+    subTasks    
+                - A task may have many subTasks of Class Task.
+                - The parentTask value must be set in the subTask.
+
+    associatedAssets    
+                - A task may have many associatedAssets of Class Asset.
+                - No costs are assigned to these assets this is for reference purposes.
+
+    inventoryMovements
+                - A task may have many inventoryMovements of Class InventoryMovement.
+
+
+#Calculated dates
+actualStartDate
+actualCompletionDate
+
+TaskType
+    Unscheduled Breakin - all work that was not scheduled, breakdowns/callouts.
+    Planned Maintenance - Planned work that is scheduled.
+    Project             - Capital expenditure upgrades or additions.
+    Turnaround          - Shutdowns, rebuilds, non Cap-Ex upgrades or additions.
+    Production Run      - Planned production that is scheduled?
+
+TaskGroup
+    ....                - custom used to groups tasks?
+    Engineering Activites
+    Production Activites
+    New Projects
+    ....                - specific shut group or turnaround etc.
+
+#Calculate missed state? 
+Missed() {
+    actualCompletionDate > targetCompletionDate
+}
+
+#External required actions.
+Show all modifications for a task.
+Show all assignedPersons for a task.
+Show all entries for a task.
+
+
Index: /branches/features/grailsUpgrade/grails-app/conf/BootStrap.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/BootStrap.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/BootStrap.groovy	(revision 875)
@@ -0,0 +1,121 @@
+class BootStrap
+{
+
+    def sessionFactory // used by isDirty().
+    def grailsApplication // used by isDirty().
+    def createDataService
+
+    def init = { servletContext ->
+
+        /** Add isDirty() to domainClasses.
+        * @todo remove after upgrading to Grails-1.3 >.
+        * See: http://grails.1312388.n4.nabble.com/beforeUpdate-Compare-with-previous-set-value-isDirty-not-working-in-Events-td1695661.html
+        */
+        addDirtyCheckMethods()
+
+        /** Environment specific settings.
+        * Note that (circa grails-1.2.2) if running "test test-app integration:" from "grails interactive"
+        * the correct environment is applied for DataSource and Config,
+        * but for BootStrap (and others) the development environment is applied.
+        */
+        environments {
+            development {
+                log.info "Starting DEVELOPMENT bootstrap."
+                createDataService.ensureSystemAndAdminAccess()
+                createDataService.createBaseData()
+                createDataService.createDemoData()
+                createDataService.startSearchableIndex()
+            }
+            test {
+                log.info "Starting TEST bootstrap."
+                createDataService.ensureSystemAndAdminAccess()
+                createDataService.createBaseData()
+                createDataService.startSearchableIndex(false)
+            }
+            production {
+                log.info "Starting PRODUCTION bootstrap."
+                createDataService.ensureSystemAndAdminAccess()
+                createDataService.createBaseData()
+                createDataService.startSearchableIndex()
+            }
+        }
+
+    } // init
+
+    def destroy = {
+    }
+
+   private void addDirtyCheckMethods() {
+      for (dc in grailsApplication.domainClasses) {
+         addDirtyCheckMethods dc.clazz.metaClass
+      }
+   }
+
+    private void addDirtyCheckMethods(metaClass) {
+      metaClass.isDirty = { ->
+         def session = sessionFactory.currentSession
+         def entry = findEntityEntry(delegate, session)
+         if (!entry) {
+            return false
+         }
+
+         Object[] values = entry.persister.getPropertyValues(delegate, session.entityMode)
+         def dirtyProperties = entry.persister.findDirty(values, entry.loadedState, delegate, session)
+         return dirtyProperties != null
+      }
+
+      metaClass.isDirty = { String fieldName ->
+         def session = sessionFactory.currentSession
+         def entry = findEntityEntry(delegate, session)
+         if (!entry) {
+            return false
+         }
+
+         Object[] values = entry.persister.getPropertyValues(delegate, session.entityMode)
+         int[] dirtyProperties = entry.persister.findDirty(values, entry.loadedState, delegate, session)
+         int fieldIndex = entry.persister.propertyNames.findIndexOf { fieldName == it }
+         return fieldIndex in dirtyProperties
+      }
+
+      metaClass.getDirtyPropertyNames = { ->
+         def session = sessionFactory.currentSession
+         def entry = findEntityEntry(delegate, session)
+         if (!entry) {
+            return []
+         }
+
+         Object[] values = entry.persister.getPropertyValues(delegate, session.entityMode)
+         int[] dirtyProperties = entry.persister.findDirty(values, entry.loadedState, delegate, session)
+         def names = []
+         for (index in dirtyProperties) {
+            names << entry.persister.propertyNames[index]
+         }
+         names
+      }
+
+      metaClass.getPersistentValue = { String fieldName ->
+         def session = sessionFactory.currentSession
+         def entry = findEntityEntry(delegate, session, false)
+         if (!entry) {
+            return null
+         }
+
+         int fieldIndex = entry.persister.propertyNames.findIndexOf { fieldName == it }
+         return fieldIndex == -1 ? null : entry.loadedState[fieldIndex]
+      }
+   }
+
+   private findEntityEntry(instance, session, boolean forDirtyCheck = true) {
+      def entry = session.persistenceContext.getEntry(instance)
+      if (!entry) {
+         return null
+      }
+
+      if (forDirtyCheck && !entry.requiresDirtyCheck(instance) && entry.loadedState) {
+         return null
+      }
+
+      entry
+   }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/conf/BuildConfig.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/BuildConfig.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/BuildConfig.groovy	(revision 875)
@@ -0,0 +1,92 @@
+grails.project.class.dir = "target/classes"
+grails.project.test.class.dir = "target/test-classes"
+grails.project.test.reports.dir	= "target/test-reports"
+
+def env = System.getProperty('grails.env')
+
+switch (env) {
+    case "production":
+        //grails.project.war.file = "target/${appName}-${appVersion}.war"
+        grails.project.war.file="target/${appName}Live.war"
+        break
+    case "development":
+        grails.project.war.file="target/${appName}Dev.war"
+        break
+    default:
+        grails.project.war.file="target/${appName}.war"
+        break
+}
+
+grails.war.resources = { stagingDir, args ->
+    // Remove some duplicate jars.
+    delete file: "${stagingDir}/WEB-INF/lib/jasperreports-2.0.5.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/jasperreports-3.1.2.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/aspectjrt-1.5.4.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/commons-digester-1.7.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/iText-2.0.8.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/iText-2.1.5.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/jfreechart-1.0.3.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/poi-3.0.2-FINAL-20080204.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/facebook-2.0.4.jar"
+    // Included by searchable plugin.
+    delete file: "${stagingDir}/WEB-INF/lib/compass-2.1.0.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/compass-2.1.0-src.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/lucene-core.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/lucene-analyzers.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/lucene-highlighter.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/lucene-queries.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/lucene-snowball.jar"
+    delete file: "${stagingDir}/WEB-INF/lib/lucene-spellchecker.jar"
+}
+
+grails.project.dependency.resolution = {
+
+    // inherit Grails' default dependencies
+    inherits( "global" ) {
+        // uncomment to disable ehcache
+        // excludes 'ehcache'
+    }
+
+    log "warn" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose'
+
+    repositories {
+        grailsPlugins()
+        grailsHome()
+
+        // uncomment the below to enable remote dependency resolution
+        // from public Maven repositories
+        //mavenLocal()
+        mavenCentral()
+        //mavenRepo "http://snapshots.repository.codehaus.org"
+        //mavenRepo "http://repository.codehaus.org"
+        //mavenRepo "http://download.java.net/maven/2/"
+        //mavenRepo "http://repository.jboss.com/maven2/"
+    }
+
+    dependencies {
+        // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
+
+        runtime 'mysql:mysql-connector-java:5.1.9'
+
+        runtime ('org.apache.poi:poi:3.5-FINAL') {
+            excludes 'servlet-api', 'commons-logging', 'log4j'
+        }
+
+        runtime ('net.sf.jasperreports:jasperreports:3.7.2') {
+            excludes 'xml-apis'
+        }
+
+        runtime ('org.compass-project:compass:2.1.4')
+        runtime ('org.apache.lucene:lucene-core:2.4.1')
+        runtime ('org.apache.lucene:lucene-analyzers:2.4.1')
+        runtime ('org.apache.lucene:lucene-highlighter:2.4.1')
+        runtime ('org.apache.lucene:lucene-queries:2.4.1')
+        runtime ('org.apache.lucene:lucene-snowball:2.4.1')
+        runtime ('org.apache.lucene:lucene-spellchecker:2.4.1')
+
+        runtime ('org.apache.ant:ant:1.7.1')
+        runtime ('org.apache.ant:ant-launcher:1.7.1')
+
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/conf/Config.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/Config.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/Config.groovy	(revision 875)
@@ -0,0 +1,409 @@
+// locations to search for config files that get merged into the main config
+// config files can either be Java properties files or ConfigSlurper scripts
+
+// grails.config.locations = [ "classpath:${appName}-config.properties",
+//                             "classpath:${appName}-config.groovy",
+//                             "file:${userHome}/.grails/${appName}-config.properties",
+//                             "file:${userHome}/.grails/${appName}-config.groovy"]
+
+// if(System.properties["${appName}.config.location"]) {
+//    grails.config.locations << "file:" + System.properties["${appName}.config.location"]
+// }
+grails.mime.file.extensions = true // enables the parsing of file extensions from URLs into the request format
+grails.mime.types = [ html: ['text/html','application/xhtml+xml'],
+                      xml: ['text/xml', 'application/xml'],
+                      text: 'text-plain',
+                      js: 'text/javascript',
+                      rss: 'application/rss+xml',
+                      atom: 'application/atom+xml',
+                      css: 'text/css',
+                      csv: 'text/csv',
+                      pdf: 'application/pdf',
+                      rtf: 'application/rtf',
+                      excel: 'application/vnd.ms-excel',
+                      ods: 'application/vnd.oasis.opendocument.spreadsheet',
+                      all: '*/*',
+                      json: ['application/json','text/json'],
+                      form: 'application/x-www-form-urlencoded',
+                      multipartForm: 'multipart/form-data'
+                    ]
+// The default codec used to encode data with ${}
+grails.views.default.codec="none" // none, html, base64
+grails.views.gsp.encoding="UTF-8"
+grails.converters.encoding="UTF-8"
+
+// enable Sitemesh preprocessing of GSP pages
+grails.views.gsp.sitemesh.preprocess = true
+// scaffolding templates configuration
+grails.scaffolding.templates.domainSuffix = 'Instance'
+
+// Set to false to use the new Grails 1.2 JSONBuilder in the render method
+grails.json.legacy.builder=false
+
+// enabled native2ascii conversion of i18n properties files
+grails.enable.native2ascii = true
+
+// whether to install the java.util.logging bridge for sl4j. Disable fo AppEngine!
+grails.logging.jul.usebridge = true
+// packages to include in Spring bean scanning
+grails.spring.bean.packages = []
+
+/**
+* Internal searchable index config.
+*/
+// Is set true by createDataService.startSearchableIndex() once bootstrap completes.
+appSearchable.cascadeOnUpdate = false
+
+/**
+* Directory configuration.
+* Pickup the Tomcat/Catalina directory else use the target or current dir.
+*/
+def fs = File.separator // Local variable.
+globalDirs.targetDir = new File("target${fs}").isDirectory() ? "target${fs}" : ''
+globalDirs.catalinaBase = System.properties.getProperty('catalina.base')
+globalDirs.logDirectory = globalDirs.catalinaBase ? "${globalDirs.catalinaBase}${fs}logs${fs}" : globalDirs.targetDir
+globalDirs.workDirectory = globalDirs.catalinaBase ? "${globalDirs.catalinaBase}${fs}work${fs}" : globalDirs.targetDir
+globalDirs.tempDirectory = globalDirs.catalinaBase ? "${globalDirs.catalinaBase}${fs}temp${fs}${appName}${fs}" : globalDirs.targetDir
+globalDirs.searchableIndexDirectory = "${globalDirs.workDirectory}SearchableIndex${fs}${appName}${fs}"
+globalDirs.tempInventoryItemPicturesDirectory = "${globalDirs.tempDirectory}InventoryItemPictures${fs}"
+
+/**
+ * Log4j configuration.
+ * Causing this file to reload (e.g. edit+save) may break the appLog destination
+ * and further logs will be written to files or directories like "[:]".
+ * For more info see http://logging.apache.org/log4j/1.2/manual.html
+ * For log levels see http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Level.html
+ * Basic log levels are ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
+ */
+
+log4j = {
+    appenders {
+        // Use if we want to prevent creation of a stacktrace.log file.
+        'null' name:'stacktrace'
+
+        // Use this if we want to modify the default appender called 'stdout'.
+        console name:'stdout', layout:pattern(conversionPattern: '[%t] %-5p %c{2} %x - %m%n')
+
+        // Custom log file.
+        rollingFile name:"appLog",
+                        file:"${globalDirs.logDirectory}${appName}.log".toString(),
+                        maxFileSize:'300kB',
+                        maxBackupIndex:1,
+                        layout:pattern(conversionPattern: '%d{[EEE, dd-MMM-yyyy @ HH:mm:ss.SSS]} [%t] %-5p %c %x - %m%n')
+    }
+
+    // This is for the built-in stuff and from the default Grails-1.2.1 config.
+    error 'org.codehaus.groovy.grails.web.servlet',  //  controllers
+            'org.codehaus.groovy.grails.web.pages', //  GSP
+            'org.codehaus.groovy.grails.web.sitemesh', //  layouts
+            'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
+            'org.codehaus.groovy.grails.web.mapping', // URL mapping
+            'org.codehaus.groovy.grails.commons', // core / classloading
+            'org.codehaus.groovy.grails.plugins', // plugins
+            'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
+            'org.springframework',
+            'org.hibernate',
+            'net.sf.ehcache.hibernate'
+
+    warn   'org.mortbay.log' // Jetty
+
+    error 'grails.app' // Set the default log level for our app code.
+    info 'grails.app.bootstrap' // Set the log level per type and per type.class
+    error 'grails.app.service.AuthService'
+    error 'grails.app.service.NavigationService'
+    error 'grails.app.service.com.zeddware.grails.plugins.filterpane.FilterService'
+    info 'org.codehaus.groovy.grails.plugins.searchable'
+    //info 'org.compass'
+    error 'grails.app.task' // Quartz jobs.
+    info 'grails.app.task.InventoryIndexJob'
+
+    // Move anything that should behave differently into this section.
+    switch(environment) {
+        case 'development':
+            // Configure the root logger to output to stdout and appLog appenders.
+            root {
+                error 'stdout','appLog'
+                additivity = true
+            }
+            //debug "org.hibernate.SQL"
+            debug 'grails.app.service'
+            debug 'grails.app.controller'
+            break
+        case 'test':
+            // Configure the root logger to only output to appLog appender.
+            root {
+                error 'stdout','appLog'
+                additivity = true
+            }
+            debug 'grails.app.service'
+            debug 'grails.app.controller'
+            break
+        case 'production':
+            // Configure the root logger to only output to appLog appender.
+            root {
+                error 'appLog'
+                additivity = true
+            }
+            warn 'grails.app.service'
+            warn 'grails.app.controller'
+            debug 'grails.app.service.AssetCsvService'
+            debug 'grails.app.service.PersonCsvService'
+            debug 'grails.app.service.InventoryCsvService'
+            info 'grails.app.service.InventoryItemService'
+            debug 'grails.app.service.AssetTreeService' /// @todo: remove after testing.
+            break
+    }
+}
+
+/**
+ * Environment specific configuration.
+ */
+environments {
+
+    production {
+        grails.serverURL = "http://www.changeme.com" // Set serverURL stem for creating absolute links.
+    }
+
+    development {
+        grails.serverURL = "http://localhost:8080/${appName}" // Set serverURL stem for creating absolute links.
+    }
+
+    test {
+        grails.serverURL = "http://localhost:8080/${appName}" // Set serverURL stem for creating absolute links.
+    }
+
+} // end environments
+
+/**
+ * Navigation plugin menu.
+ * The top level titles are taken from i18n message bundles.
+ * Subitems i18n message bundles are not currently resolving with this plugin.
+ */
+navigation.nav = [
+    [order:10, controller:'appCore', title:'home', action:'start',
+        subItems: [
+            [order:10, controller:'appCore', title:'Start', action:'start', isVisible: { true }],
+            [order:20, controller:'appCore', title:'Manager', action:'manager', isVisible: {
+                    authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager,ROLE_InventoryManager,ROLE_AssetManager,ROLE_ProductionManager')
+                }
+            ],
+            [order:30, controller:'appCore', title:'Admin', action:'appAdmin', isVisible: { authenticateService.ifAllGranted('ROLE_AppAdmin') }],
+            [order:90, controller:'appCore', title:'Timeout', action:'changeSessionTimeout', isVisible: { params.action == 'changeSessionTimeout' }],
+            [order:91, controller:'appCore', title:'Password', action:'changePassword', isVisible: { params.action == 'changePassword' }],
+        ]
+    ],
+    [order:20, controller:'taskDetailed', title:'tasks', action:'search',
+        subItems: [
+            [order:10, controller:'taskDetailed', title:'Search', action:'search', isVisible: { true }],
+            [order:11, controller:'taskDetailed', title:'Calendar', action:'searchCalendar', isVisible: { true }],
+            [order:20, controller:'taskDetailed', title:'+Scheduled', action:'create', isVisible: { true }],
+            [order:30, controller:'taskDetailed', title:'+Unsheduled', action:'createUnscheduled', isVisible: { true }],
+            [order:40, controller:'taskDetailed', title:'+Callout', action:'createImmediateCallout', isVisible: { true }],
+            [order:90, controller:'taskDetailed', title:'Show', action:'show', id:'nav', isVisible: { params.action == 'show' }],
+            [order:91, controller:'taskDetailed', title:'Edit', action:'edit', id:'nav', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:30, controller:'inventoryItemDetailed', title:'inventory', action:'search',
+        subItems: [
+            [order:10, controller:'inventoryItemDetailed', title:'Search', action:'search', isVisible: { true }],
+            [order:20, controller:'inventoryItemDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'inventoryItemDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'inventoryItemDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }],
+            [order:91, controller:'inventoryItemDetailed', title:'Reorder', action:'reorder', isVisible: { params.action == 'reorder' }]
+        ]
+    ],
+    [order:40, controller:'assetDetailed', title:'assets', action:'search',
+        subItems: [
+            [order:10, controller:'assetDetailed', title:'Search', action:'search', isVisible: { true }],
+            [order:20, controller:'assetDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'assetDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'assetDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }],
+            [order:99, controller:'assetSubItemDetailed', title:'Sub Items', action:'search', isVisible: { true }]
+        ]
+    ]
+]
+
+/**
+ * Navigation plugin alternate menu.
+ * The alternate menu top level titles are not displayed anywhere.
+ * Subitems i18n message bundles are not currently resolving with this plugin.
+ */
+navigation.navAlt = [
+    [order:10, controller:'person', title:'person', action:'list',
+        subItems: [
+            [order:10, controller:'person', title:'Person List', action:'list', isVisible: { true }],
+            [order:20, controller:'person', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'person', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'person', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:20, controller:'taskProcedureDetailed', title:'taskProcedure', action:'list',
+        subItems: [
+            [order:10, controller:'taskProcedureDetailed', title:'Task Procedure List', action:'list', isVisible: { true }],
+            [order:20, controller:'taskProcedureDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'taskProcedureDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'taskProcedureDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:30, controller:'assetSubItemDetailed', title:'assetSubItem', action:'search',
+        subItems: [
+            [order:10, controller:'assetSubItemDetailed', title:'Sub Item Search', action:'search', isVisible: { true }],
+            [order:20, controller:'assetSubItemDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'assetSubItemDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'assetSubItemDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:40, controller:'maintenancePolicyDetailed', title:'maintenancePolicy', action:'list',
+        subItems: [
+            [order:10, controller:'maintenancePolicyDetailed', title:'Maintenance Policy List', action:'list', isVisible: { true }],
+            [order:20, controller:'maintenancePolicyDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'maintenancePolicyDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'maintenancePolicyDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:50, controller:'supplierDetailed', title:'supplier', action:'list',
+        subItems: [
+            [order:10, controller:'supplierDetailed', title:'Supplier List', action:'list', isVisible: { true }],
+            [order:20, controller:'supplierDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'supplierDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'supplierDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:70, controller:'inventoryStoreDetailed', title:'inventoryStore', action:'list',
+        subItems: [
+            [order:10, controller:'inventoryStoreDetailed', title:'Inventory Store List', action:'list', isVisible: { true }],
+            [order:20, controller:'inventoryStoreDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'inventoryStoreDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'inventoryStoreDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:80, controller:'inventoryLocationDetailed', title:'inventoryLocation', action:'list',
+        subItems: [
+            [order:10, controller:'inventoryLocationDetailed', title:'Inventory Location List', action:'list', isVisible: { true }],
+            [order:20, controller:'inventoryLocationDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'inventoryLocationDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'inventoryLocationDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:90, controller:'inventoryGroupDetailed', title:'inventoryGroup', action:'list',
+        subItems: [
+            [order:10, controller:'inventoryGroupDetailed', title:'Inventory Group List', action:'list', isVisible: { true }],
+            [order:20, controller:'inventoryGroupDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'inventoryGroupDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'inventoryGroupDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:110, controller:'supplierTypeDetailed', title:'supplierType', action:'list',
+        subItems: [
+            [order:10, controller:'supplierTypeDetailed', title:'Supplier Type List', action:'list', isVisible: { true }],
+            [order:20, controller:'supplierTypeDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'supplierTypeDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'supplierTypeDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:120, controller:'siteDetailed', title:'site', action:'list',
+        subItems: [
+            [order:10, controller:'siteDetailed', title:'Site List', action:'list', isVisible: { true }],
+            [order:20, controller:'siteDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'siteDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'siteDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:130, controller:'sectionDetailed', title:'section', action:'list',
+        subItems: [
+            [order:10, controller:'sectionDetailed', title:'Section List', action:'list', isVisible: { true }],
+            [order:20, controller:'sectionDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'sectionDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'sectionDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:140, controller:'extendedAttributeTypeDetailed', title:'extendedAttributeType', action:'list',
+        subItems: [
+            [order:10, controller:'extendedAttributeTypeDetailed', title:'Attribute Type List', action:'list', isVisible: { true }],
+            [order:20, controller:'extendedAttributeTypeDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'extendedAttributeTypeDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'extendedAttributeTypeDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:150, controller:'departmentDetailed', title:'department', action:'list',
+        subItems: [
+            [order:10, controller:'departmentDetailed', title:'Department List', action:'list', isVisible: { true }],
+            [order:20, controller:'departmentDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'departmentDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'departmentDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:160, controller:'productionReferenceDetailed', title:'productionReference', action:'list',
+        subItems: [
+            [order:10, controller:'productionReferenceDetailed', title:'Production Reference List', action:'list', isVisible: { true }],
+            [order:20, controller:'productionReferenceDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'productionReferenceDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'productionReferenceDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:170, controller:'costCodeDetailed', title:'costCode', action:'list',
+        subItems: [
+            [order:10, controller:'costCodeDetailed', title:'Cost Code List', action:'list', isVisible: { true }],
+            [order:20, controller:'costCodeDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'costCodeDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'costCodeDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:180, controller:'personGroupDetailed', title:'personGroup', action:'list',
+        subItems: [
+            [order:10, controller:'personGroupDetailed', title:'Person Group List', action:'list', isVisible: { true }],
+            [order:20, controller:'personGroupDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'personGroupDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'personGroupDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:190, controller:'personGroupTypeDetailed', title:'personGroupType', action:'list',
+        subItems: [
+            [order:10, controller:'personGroupTypeDetailed', title:'Person Group Type List', action:'list', isVisible: { true }],
+            [order:20, controller:'personGroupTypeDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'personGroupTypeDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'personGroupTypeDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:200, controller:'taskGroupDetailed', title:'taskProcedure', action:'list',
+        subItems: [
+            [order:10, controller:'taskGroupDetailed', title:'Task Group List', action:'list', isVisible: { true }],
+            [order:20, controller:'taskGroupDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'taskGroupDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'taskGroupDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:210, controller:'unitOfMeasureDetailed', title:'unitOfMeasure', action:'list',
+        subItems: [
+            [order:10, controller:'unitOfMeasureDetailed', title:'Unit Of Measure List', action:'list', isVisible: { true }],
+            [order:20, controller:'unitOfMeasureDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'unitOfMeasureDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'unitOfMeasureDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:220, controller:'inventoryItemPurchaseDetailed', title:'inventoryItemPurchase', action:'search',
+        subItems: [
+            [order:10, controller:'inventoryItemPurchaseDetailed', title:'Purchase Search', action:'search', isVisible: { true }],
+            [order:20, controller:'inventoryItemPurchaseDetailed', title:'Order', action:'create', isVisible: { true }],
+            [order:90, controller:'inventoryItemPurchaseDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'inventoryItemPurchaseDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ],
+    [order:230, controller:'purchasingGroupDetailed', title:'purchasingGroup', action:'list',
+        subItems: [
+            [order:10, controller:'purchasingGroupDetailed', title:'Purchasing Group List', action:'list', isVisible: { true }],
+            [order:20, controller:'purchasingGroupDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:90, controller:'purchasingGroupDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
+            [order:91, controller:'purchasingGroupDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
+        ]
+    ]
+]
+
+/**
+ * Custom application global settings.
+ * @todo: externalise these settings to a config file (along with the database settings) or have them configurable via the web interface+database.
+ */
+taskRecurringScheduleJob.repeatInterval=10
+// It is recommended to limit the currencyList to the one that the site uses e.g: currencyList = ['AUD']
+currencyList = ['EUR', 'XCD', 'USD', 'XOF', 'NOK', 'AUD', 'XAF', 'NZD', 'MAD', 'DKK', 'GBP', 'CHF', 'XPF', 'ILS', 'ROL', 'TRL']
+
Index: /branches/features/grailsUpgrade/grails-app/conf/DataSource.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/DataSource.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/DataSource.groovy	(revision 875)
@@ -0,0 +1,83 @@
+dataSource {
+    // Open separate connections to database for every request or pool connections.
+    pooled = true
+}
+hibernate {
+    cache.use_second_level_cache=true
+    cache.use_query_cache=true
+    cache.provider_class='net.sf.ehcache.hibernate.EhCacheProvider'
+}
+
+// dbCreate options.
+// create-drop: Drop and re-create the database tables on restart. Deletes existing data.
+// create:       Create the database if it doesn't exist, but don't modify it if it does. Deletes existing data.
+// update:     Create the database if it doesn't exist, and modify it if it does exist. Keep data.
+// If nothing specified then do nothing to database schema.
+
+// Environment specific settings.
+environments {
+    development {
+        dataSource {
+            /** HSQLDB - In memory */
+            driverClassName = "org.hsqldb.jdbcDriver"
+            username = "sa"
+            password = ""
+            dbCreate = "create-drop"
+            url = "jdbc:hsqldb:mem:devDb"
+            /** MySQL */
+//             driverClassName = "com.mysql.jdbc.Driver"
+//             username = "gnumimsadmin"
+//             password = "gnumimsadmin"
+//             dbCreate = "create-drop"
+//             url = "jdbc:mysql://host:3306/gnumims_dev?autoReconnect=true&sessionVariables=storage_engine=InnoDB"
+        }
+    }
+    test {
+        dataSource {
+            /** HSQLDB - In memory */
+            driverClassName = "org.hsqldb.jdbcDriver"
+            username = "sa"
+            password = ""
+            dbCreate = "update"
+            url = "jdbc:hsqldb:mem:devDb"
+            /** MySQL */
+//             driverClassName = "com.mysql.jdbc.Driver"
+//             username = "gnumimsadmin"
+//             password = "gnumimsadmin"
+//             dbCreate = "update"
+//             url = "jdbc:mysql://host:3306/gnumims_test?autoReconnect=true&sessionVariables=storage_engine=InnoDB"
+        }
+    }
+    production {
+        dataSource {
+            /* Delete dbCreate line after setup! */
+            /** HSQLDB - In memory */
+//             driverClassName = "org.hsqldb.jdbcDriver"
+//             username = "sa"
+//             password = ""
+//             dbCreate = "create-drop"
+//             url = "jdbc:hsqldb:mem:devDb"
+            /** HSQLDB - In file */
+//             driverClassName = "org.hsqldb.jdbcDriver"
+//             username = "sa"
+//             password = ""
+//             dbCreate = "update"
+//             url = "jdbc:hsqldb:file:prodDb;shutdown=true"
+            /** MSSQL */
+            //For more info see the docs that you downloaded with the driver.
+//             dialect = org.hibernate.dialect.SQLServerDialect // Useful with `grails schema-export`
+//             driverClassName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"
+//             username = "gnumimsadmin"
+//             password = "gnumimsadmin"
+//             dbCreate = "update"
+//             url = "jdbc:sqlserver://gnumimssql01:1433;databaseName=gnumims_prod"
+            /** MySQL */
+            driverClassName = "com.mysql.jdbc.Driver"
+            username = "gnumimsadmin"
+            password = "gnumimsadmin"
+            dbCreate = "update"
+            url = "jdbc:mysql://gnumimssql01:3306/gnumims_prod?autoReconnect=true&sessionVariables=storage_engine=InnoDB"
+        }
+
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/conf/NoCacheFilters.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/NoCacheFilters.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/NoCacheFilters.groovy	(revision 875)
@@ -0,0 +1,26 @@
+class NoCacheFilters {
+
+    def filters = {
+        all(controller:'*', action:'*') {
+            before = {
+                
+                //Turn off as much caching as we can.
+                response.setHeader("Cache-Control", "no-cache,no-store,must-revalidate")// HTTP 1.1
+                response.addDateHeader('Expires', 0)
+                response.setDateHeader('max-age', 0)
+                response.setIntHeader ('Expires', -1) //prevents caching at the proxy server
+                response.addHeader('cache-Control', 'private') //IE5.x only 
+                response.addHeader('Pragma', 'no-cache') //HTTP 1.0
+
+            }
+
+            after = {
+                
+            }
+            afterView = {
+                
+            }
+        }
+    }
+    
+}
Index: /branches/features/grailsUpgrade/grails-app/conf/Searchable.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/Searchable.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/Searchable.groovy	(revision 875)
@@ -0,0 +1,168 @@
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+
+/**
+ * This {@link groovy.util.ConfigObject} script provides Grails Searchable Plugin configuration.
+ *
+ * You can use the "environments" section at the end of the file to define per-environment
+ * configuration.
+ *
+ * Note it is NOT required to add a reference to this file in Config.groovy; it is loaded by
+ * the plugin itself.
+ *
+ * Available properties in the binding are:
+ *
+ * @param userHome The current user's home directory.
+ *                 Same as System.properties['user.home']
+ * @param appName The Grails environment (ie, "development", "test", "production").
+ *                Same as System.properties['grails.env']
+ * @param appVersion The version of your application
+ * @param grailsEnv The Grails environment (ie, "development", "test", "production").
+ *                  Same as System.properties['grails.env']
+ *
+ * You can also use System.properties to refer to other JVM properties.
+ *
+ * This file is created by "grails install-searchable-config", and replaces
+ * the previous "SearchableConfiguration.groovy"
+ */
+searchable {
+
+    /**
+    * The location of the Compass index
+    *
+    * Examples: "/home/app/compassindex", "ram://app-index" or null to use the default
+    *
+    * The default is "${user.home}/.grails/projects/${app.name}/searchable-index/${grails.env}"
+    */
+    compassConnection = new File(ConfigurationHolder.config.globalDirs.searchableIndexDirectory).absolutePath
+
+    /**
+     * Any settings you wish to pass to Compass
+     *
+     * Use this to configure custom/override default analyzers, query parsers, eg
+     *
+     *     Map compassSettings = [
+     *         'compass.engine.analyzer.german.type': 'German'
+     *     ]
+     *
+     * gives you an analyzer called "german" you can then use in mappings and queries, like
+     *
+     *    class Book {
+     *        static searchable = { content analyzer: 'german' }
+     *        String content
+     *    }
+     *
+     *    Book.search("unter", analyzer: 'german')
+     *
+     * Documentation for Compass settings is here: http://www.compass-project.org/docs/2.1.0M2/reference/html/core-settings.html
+     */
+    compassSettings = [:]
+
+    /**
+     * Default mapping property exclusions
+     *
+     * No properties matching the given names will be mapped by default
+     * ie, when using "searchable = true"
+     *
+     * This does not apply for classes using "searchable = [only/except: [...]]"
+     * or mapping by closure
+     */
+    defaultExcludedProperties = ["password"]
+
+    /**
+     * Default property formats
+     *
+     * Value is a Map between Class and format string, eg
+     *
+     *     [(Date): "yyyy-MM-dd'T'HH:mm:ss"]
+     *
+     * Only applies to class properties mapped as "searchable properties", which are typically
+     * simple class types that can be represented as Strings (rather than references
+     * or components) AND only required if overriding the built-in format.
+     */
+    defaultFormats = [:]
+
+    /**
+     * Set default options for each SearchableService/Domain-class method, by method name.
+     *
+     * These can be overriden on a per-query basis by passing the method a Map of options
+     * containing those you want to override.
+     *
+     * You may want to customise the options used by the search method, which are:
+     *
+     * @param reload          whether to reload domain class instances from the DB: true|false
+     *                        If true, the search  will be slower but objects will be associated
+     *                        with the current Hibernate session
+     * @param escape          whether to escape special characters in string queries: true|false
+     * @param offset          the 0-based hit offset of the first page of results.
+     *                        Normally you wouldn't change it from 0, it's only here because paging
+     *                        works by using an offset + max combo for a specific page
+     * @param max             the page size, for paged search results
+     * @param defaultOperator if the query does not otherwise indicate, then the default operator
+     *                        applied: "or" or "and".
+     *                        If "and" means all terms are required for a match, if "or" means
+     *                        any term is required for a match
+     * @param suggestQuery    if true and search method is returning a search-result object
+     *                        (rather than a domain class instance, list or count) then a
+     *                        "suggestedQuery" property is also added to the search-result.
+     *                        This can also be a Map of options as supported by the suggestQuery
+     *                        method itself
+     *
+     * For the options supported by other methods, please see the documentation
+     * http://grails.org/Searchable+Plugin
+     */
+    defaultMethodOptions = [
+        search: [reload: false, escape: false, offset: 0, max: 10, defaultOperator: "and"],
+        suggestQuery: [userFriendly: true]
+    ]
+
+    /**
+     * Should changes made through GORM/Hibernate be mirrored to the index
+     * automatically (using Compass::GPS)?
+     *
+     * If false, you must manage the index manually using index/unindex/reindex
+     */
+    mirrorChanges = false
+
+    /**
+     * Should the database be indexed at startup (using Compass:GPS)?
+     *
+     * Possible values: true|false|"fork"
+     *
+     * The value may be a boolean true|false or a string "fork", which means true,
+     * and fork a thread for it
+     *
+     * If you use BootStrap.groovy to insert your data then you should use "true",
+     * which means do a non-forking, otherwise "fork" is recommended
+     */
+    bulkIndexOnStartup = false
+
+    /**
+     * Should index locks be removed (if present) at startup?
+     */
+    releaseLocksOnStartup = true
+}
+
+// per-environment settings
+environments {
+    development {
+        searchable {
+            // development is default; inherits from above
+        }
+    }
+
+    test {
+        searchable {
+            // disable bulk index on startup
+            bulkIndexOnStartup = false
+
+            // use faster in-memory index
+            compassConnection = "ram://test-index"
+        }
+    }
+
+    production {
+        searchable {
+            // add your production settings here
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/conf/SecurityConfig.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/SecurityConfig.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/SecurityConfig.groovy	(revision 875)
@@ -0,0 +1,89 @@
+security {
+
+    def authenticateService
+
+	// See DefaultSecurityConfig.groovy for all settable/overridable properties
+
+	active = true
+
+	loginUserDomainClass = "Person"
+    userName = 'loginName'
+    password = 'password'
+    enabled = 'isActive'
+
+	authorityDomainClass = "Authority"
+
+    // Required if we want to run "grails generate-manager"
+    // Which recreates the controller and views, so save the views!
+//     requestMapClass = 'Requestmap'
+
+    // The whole application relies on controllerAnnotations and the static rules bellow.
+    useRequestMapDomainClass = false
+    useControllerAnnotations = true
+
+    // Set true especially if used across the internet.
+    forceHttps = 'false'
+
+    // Pessimistic locking, deny access to all URLs that don't 
+    // have an applicable URL-Role configuration.
+    // This forces us to set an annotation, static rule or
+    // extend BaseController and prevents accidentally leaving pages open.
+    controllerAnnotationsRejectIfNoRule = true
+
+    // Static rules for controllers, actions and urls.
+    // Since we are using pessimistic locking we have to set some things
+    // here but most security should be set in the controllers.
+    controllerAnnotationStaticRules = [
+    '/': ['IS_AUTHENTICATED_FULLY'],
+    '/index.gsp': ['IS_AUTHENTICATED_FULLY'],
+    '/css/*': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/images/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/js/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/plugins/**': ['IS_AUTHENTICATED_FULLY'],
+    '/plugins/*/images/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/plugins/*/css/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/plugins/*/js/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/classDiagram*': ['IS_AUTHENTICATED_FULLY'],
+    '/classDiagram/**': ['IS_AUTHENTICATED_FULLY'],
+    '/login*': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/login/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
+    '/logout*': ['IS_AUTHENTICATED_FULLY'],
+    '/logout/**': ['IS_AUTHENTICATED_FULLY'],
+    '/image*': ['IS_AUTHENTICATED_FULLY'],
+    '/image/**': ['IS_AUTHENTICATED_FULLY'],
+    '/reports*': ['IS_AUTHENTICATED_FULLY'],
+    '/reports/**': ['IS_AUTHENTICATED_FULLY'],
+    '/jasper*': ['IS_AUTHENTICATED_FULLY'],
+    '/jasper/**': ['IS_AUTHENTICATED_FULLY']
+    ]
+
+    // Always call the welcome action so that bookmarks are not used, a
+    // welcome message can be populated and the sessionTimeout can be set.
+    defaultTargetUrl = '/appCore/welcome'
+    alwaysUseDefaultTargetUrl = true
+
+    // User caching, turned this off so that password changes take effect.
+    // It would appear that user is still in the session as logout/login
+    // is still required for role changes to take effect.
+    // If this option causes high database load try:
+    //  import org.acegisecurity.providers.dao.DaoAuthenticationProvider
+    //  import org.acegisecurity.context.SecurityContextHolder
+    //  DaoAuthenticationProvider daoAuthenticationProvider 
+    //  def user = SecurityContextHolder.context.authentication.principal.username 
+    //  daoAuthenticationProvider.userCache.removeUserFromCache(user)
+    //  in logout controller and perhaps on password change and role change.
+    cacheUsers = false
+
+//    // Listen for events and run the closure(s) that follow.
+//    // Unfortunately the session is not available yet so many things can't be done here, use a defaultTargetUrl and controller.
+//    useSecurityEventListener = true
+//
+//    onAuthenticationSuccessEvent = { e, appCtx ->
+//        def p = e.source.principal
+//        def personInstance = Person.findByLoginName(p.username)
+//        println p.username
+//        println personInstance.loginName
+//        println personInstance.firstName
+//    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/conf/UrlMappings.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/UrlMappings.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/UrlMappings.groovy	(revision 875)
@@ -0,0 +1,20 @@
+class UrlMappings {
+    static mappings = {
+        "/$controller/$action?/$id?"{
+            constraints {
+                // apply constraints here
+            }
+        }
+
+        "/image/$id/$size?/$filename?" {
+            constraints {
+                size(matches: /\d+/)
+            }
+            controller = 'pictureDetailed'
+            action = 'view'
+        }
+
+        "/"(view:"/index")
+        "500"(view:'/error')
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/conf/spring/resources.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/conf/spring/resources.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/conf/spring/resources.groovy	(revision 875)
@@ -0,0 +1,4 @@
+// Place your Spring DSL code here
+beans = {
+    
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/AddressDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AddressDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AddressDetailedController.groovy	(revision 875)
@@ -0,0 +1,115 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                    'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager'])
+class AddressDetailedController extends BaseController {
+
+    def addressService
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager', 'ROLE_AppUser'])
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager', 'ROLE_AppUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ addressInstanceList: Address.list( params ), addressInstanceTotal: Address.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager', 'ROLE_AppUser'])
+    def show = {
+        def addressInstance = Address.get( params.id )
+
+        if(!addressInstance) {
+            flash.message = "Address not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ addressInstance : addressInstance ] }
+    }
+
+    def delete = {
+        def addressInstance = Address.get( params.id )
+        if(addressInstance) {
+            try {
+                addressInstance.delete(flush:true)
+                flash.message = "Address ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "Address ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "Address not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def addressInstance = Address.get( params.id )
+
+        if(!addressInstance) {
+            flash.message = "Address not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ addressInstance : addressInstance ]
+        }
+    }
+
+    def update = {
+        def addressInstance = Address.get( params.id )
+        if(addressInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(addressInstance.version > version) {
+
+                    addressInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[addressInstance:addressInstance])
+                    return
+                }
+            }
+            addressInstance.properties = params
+            if(!addressInstance.hasErrors() && addressInstance.save(flush: true)) {
+                flash.message = "Address ${params.id} updated"
+                redirect(action:show,id:addressInstance.id)
+            }
+            else {
+                render(view:'edit',model:[addressInstance:addressInstance])
+            }
+        }
+        else {
+            flash.message = "Address not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def result = addressService.create(params)
+
+        if(!result.error)
+            return [addressInstance: result.addressInstance]
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: list)
+    }
+
+    def save = {
+        def result = addressService.save(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["Address", result.addressInstance.id])
+            redirect(action:show, id: result.addressInstance.id)
+            return
+        }
+
+        render(view:'create', model:[addressInstance: result.addressInstance])
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/AppConfigController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AppConfigController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AppConfigController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class AppConfigController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ appConfigInstanceList: AppConfig.list( params ), appConfigInstanceTotal: AppConfig.count() ]
+    }
+
+    def show = {
+        def appConfigInstance = AppConfig.get( params.id )
+
+        if(!appConfigInstance) {
+            flash.message = "AppConfig not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ appConfigInstance : appConfigInstance ] }
+    }
+
+    def delete = {
+        def appConfigInstance = AppConfig.get( params.id )
+        if(appConfigInstance) {
+            try {
+                appConfigInstance.delete(flush:true)
+                flash.message = "AppConfig ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "AppConfig ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "AppConfig not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def appConfigInstance = AppConfig.get( params.id )
+
+        if(!appConfigInstance) {
+            flash.message = "AppConfig not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ appConfigInstance : appConfigInstance ]
+        }
+    }
+
+    def update = {
+        def appConfigInstance = AppConfig.get( params.id )
+        if(appConfigInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(appConfigInstance.version > version) {
+                    
+                    appConfigInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[appConfigInstance:appConfigInstance])
+                    return
+                }
+            }
+            appConfigInstance.properties = params
+            if(!appConfigInstance.hasErrors() && appConfigInstance.save(flush: true)) {
+                flash.message = "AppConfig ${params.id} updated"
+                redirect(action:show,id:appConfigInstance.id)
+            }
+            else {
+                render(view:'edit',model:[appConfigInstance:appConfigInstance])
+            }
+        }
+        else {
+            flash.message = "AppConfig not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def appConfigInstance = new AppConfig()
+        appConfigInstance.properties = params
+        return ['appConfigInstance':appConfigInstance]
+    }
+
+    def save = {
+        def appConfigInstance = new AppConfig(params)
+        if(!appConfigInstance.hasErrors() && appConfigInstance.save(flush: true)) {
+            flash.message = "AppConfig ${appConfigInstance.id} created"
+            redirect(action:show,id:appConfigInstance.id)
+        }
+        else {
+            render(view:'create',model:[appConfigInstance:appConfigInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/AppCoreController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AppCoreController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AppCoreController.groovy	(revision 875)
@@ -0,0 +1,321 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.*
+import org.apache.commons.lang.WordUtils
+
+/**
+* Controller class for the application core views.
+*/
+class AppCoreController extends BaseController {
+
+    def authService
+    def assetService
+    def appConfigService
+    def createDataService
+    def searchableService
+    def assetSubItemService
+    def createBulkDataService
+
+    def index = { redirect(action:start,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    //def allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    /**
+    * This is where we arrive after login.
+    *  Attach the welcome flash message and redirect to where ever we want the user to start.
+    * e.g. redirect(controller:"taskDetailed", action:"search")
+    */
+    def welcome = {
+        def personInstance = authService.currentUser
+        flash.message = "Welcome, ${personInstance.firstName} ${personInstance.lastName}."
+
+        def sess = getSession()
+        sess.setMaxInactiveInterval(personInstance.sessionTimeout)
+        redirect(action:start)
+    }
+
+    /**
+    * Render the start view.
+    */
+    def start = {
+        def grailsVersion = grailsApplication.metadata['app.grails.version']
+        def applicationVersion = grailsApplication.metadata['app.version']
+        def applicationName = grailsApplication.metadata['app.name']
+        def applicationVcsRevision = grailsApplication.metadata['app.vcsRevision']
+
+        // Build the application string.
+        def applicationString = WordUtils.capitalize(applicationName)
+        if(applicationVersion)
+            applicationString += "-" + applicationVersion
+        if(applicationVcsRevision) {
+            if(applicationVcsRevision.size() > 7)  { // Svn's $Rev: NUM $
+                applicationVcsRevision = applicationVcsRevision[6..-3]
+                applicationString += " (rev " + applicationVcsRevision + ")"
+            }
+            else
+                applicationString += " (" + applicationVcsRevision + ")"
+        }
+
+        // Build the plugins string.
+        def pluginProperties = grailsApplication.metadata.findAll {it.key.contains('plugin')}
+        pluginProperties.each() {
+            it.key = WordUtils.capitalize( (it.key + GString.EMPTY).split("\\.")[-1] )
+        }
+        pluginProperties = pluginProperties.sort { p1, p2 -> p1.key.compareToIgnoreCase(p2.key) }
+        def plugins = pluginProperties.collect{ it.key + '-' + it.value }.join(", ")
+
+        def sections = Section.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+        def showTab = [:]
+        switch (params.showTab) {
+            case "showReportsTab":
+                showTab.reports =  new String("true")
+                break
+            case "showOptionsTab":
+                showTab.Options =  new String("true")
+                break
+            case "showAboutTab":
+                showTab.about =  new String("true")
+                break
+            default:
+                showTab.quickLinks = new String("true")
+        }
+
+        return [grailsVersion: grailsVersion,
+                    applicationString: applicationString,
+                    plugins: plugins,
+                    sections: sections,
+                    showTab: showTab]
+    }
+
+    /**
+    * Allow a person to change their session timeout setting.
+    */
+    def changeSessionTimeout = {
+        if (request.method == 'GET') {
+            def personInstance = authService.currentUser
+            return [ personInstance : personInstance ]       
+        }
+        if (request.method == 'POST') {
+            def personInstance = authService.currentUser
+                personInstance.properties = params
+                if (!personInstance.hasErrors() && personInstance.save(flush: true)) {
+                    def sess = getSession()
+                    sess.setMaxInactiveInterval(personInstance.sessionTimeout)
+                    flash.message = "Session timeout changed."
+                    redirect(action:start)
+                }
+                else {
+                    render(view:'changeSessionTimeout',model:[personInstance:personInstance])
+                }
+        }
+    }
+
+    /**
+    * Allow a person to change their password.
+    */
+    def changePassword = {
+        //def principal = authenticateService.principal()
+        //log.info principal.getAuthorities()
+
+        if (request.method == 'GET') {
+            def personInstance = authService.currentUser
+            return [ personInstance : personInstance ]       
+        }
+
+        if (request.method == 'POST') {
+            def personInstance = authService.currentUser
+
+            if(params.confirmPass == params.pass) {
+                personInstance.pass = params.pass
+                personInstance.password = authService.encodePassword(personInstance.pass)
+
+                if (!personInstance.hasErrors() && personInstance.save(flush: true)) {
+                    //userCache.removeUserFromCache(personInstance.loginName)
+                    flash.message = "Password changed successfully."
+                    redirect(action:start)
+                }
+                else {
+                    render(view:'changePassword',model:[personInstance:personInstance])
+                }
+            }
+            else {
+                personInstance.errors.reject('person.pass.doesNotMatch',            // Error code, see grails-app/i18n/message.properties
+                                                                ['pass', 'class Person'].toArray(),      // Groovy ListArray cast to Object[]
+                                                                 '[NothingUseMessageProperites]')  // Default mapping string.
+                render(view:'changePassword',model:[personInstance:personInstance])
+            }
+
+        }
+    }
+
+    /**
+    * Render the manager view for manager or admin roles.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager'])
+    def manager = {
+    }
+
+    /**
+    * Render the appAdmin view for admin roles.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def appAdmin = {
+
+        def offerBaseDataCreation = false
+        def offerDemoDataCreation = false
+        def baseDataCreated = appConfigService.exists("baseDataCreated")
+        def demoDataCreated = appConfigService.exists("demoDataCreated")
+        def demoDataCreationDisabled = appConfigService.exists("demoDataCreationDisabled")
+
+        if(!baseDataCreated)
+            offerBaseDataCreation = true
+
+        if(baseDataCreated && !demoDataCreated && !demoDataCreationDisabled)
+            offerDemoDataCreation = true
+
+        return[baseDataCreated: baseDataCreated,
+                        demoDataCreated: demoDataCreated,
+                        offerDemoDataCreation: offerDemoDataCreation,
+                        offerBaseDataCreation: offerBaseDataCreation,
+                        demoDataCreationDisabled: demoDataCreationDisabled]
+    }
+
+    /**
+    * Allow admin to disable demo data creation.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def disableDemoDataCreation = {
+        if(!appConfigService.set("demoDataCreationDisabled")) {
+            flash.message = "Demo data creation could not be disabled."
+            redirect(action: appAdmin)
+            return
+        }
+
+        // Success.
+        flash.message = "Demo data creation disabled."
+        redirect(action: appAdmin)
+    }
+
+    /**
+    * Allow admin to create base data.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def createBaseData = {
+        if(!createDataService.createBaseData()) {
+            flash.message = "Base data could not be created."
+            redirect(action: appAdmin)
+            return
+        }
+
+        // Success.
+        flash.message = "Base data created."
+        redirect(action: appAdmin)
+    }
+
+    /**
+    * Allow admin to create demo data.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def createDemoData = {
+        if(!createDataService.createDemoData()) {
+            flash.message = "Demo data could not be created."
+            redirect(action: appAdmin)
+            return
+        }
+
+        // Success.
+        flash.message = "Demo data created."
+        redirect(action: appAdmin)
+    }
+
+    /**
+    * Allow admin to create bulk test data.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def createBulkTestData = {
+        def result = createBulkDataService.createAll()
+        if(!result.error) {
+            flash.message = g.message(code:"default.create.success", args:["Bulk test data", ''])
+            redirect(action: appAdmin)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: appAdmin)
+    }
+
+    /**
+    * Allow admin to create bulk inventory test data.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def createBulkInventoryTestData = {
+        def result = createBulkDataService.createBulkInventoryTestData()
+        if(!result.error) {
+            flash.message = g.message(code:"default.create.success", args:["Bulk test data", ''])
+            redirect(action: appAdmin)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: appAdmin)
+    }
+
+    /**
+    * Render the application log file.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager'])
+    def appLog = {
+        def file = new File(ConfigurationHolder.config.log4j.appenders.appLog.file)
+
+        // Success.
+        [log: file.text]
+    }
+
+    /**
+    * Rebuild the text search index.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager'])
+    def rebuildTextSearchIndex = {
+        InventoryIndexJob.triggerNow(['calledBy':'AppCoreController rebuildTextSearchIndex{}'])
+
+        flash.message = g.message(code:"appCore.rebuild.text.search.index")
+        redirect(action: manager)
+    }
+
+    /**
+    * Allow admin to create recommended extended attributes for assets.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def createRecommendedAssetExtendedAttributes = {
+        def result = assetService.createRecommendedExtendedAttributes()
+        if(!result.error) {
+            flash.message = g.message(code:"default.create.success", args:["Extended attributes created", ''])
+            redirect(action: appAdmin)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: appAdmin)
+    }
+
+    /**
+    * Allow admin to create recommended extended attributes for level 1 assetSubItems.
+    */
+    @Secured(['ROLE_AppAdmin'])
+    def createRecommendedAssetSubItemExtendedAttributes = {
+        def result = assetSubItemService.createRecommendedExtendedAttributes()
+        if(!result.error) {
+            flash.message = g.message(code:"default.create.success", args:["Extended attributes created", ''])
+            redirect(action: appAdmin)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: appAdmin)
+    }
+
+} // end of class.
Index: /branches/features/grailsUpgrade/grails-app/controllers/AssetDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AssetDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AssetDetailedController.groovy	(revision 875)
@@ -0,0 +1,399 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import org.apache.commons.lang.WordUtils
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class AssetDetailedController extends BaseController {
+
+    def assetCsvService
+    def filterService
+    def exportService
+    def assetService
+    def assetTreeService
+    def taskService
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST', saveCopy:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def index = { redirect(action:search,params:params) }
+
+    /**
+    * Set session.assetSearchParamsMax
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def setSearchParamsMax = {
+        def max = 1000
+        if(params.newMax?.isInteger()) {
+            def i = params.newMax.toInteger()
+            if(i > 0 && i <= max)
+                session.assetSearchParamsMax = params.newMax
+            if(i > max)
+                session.assetSearchParamsMax = max
+        }
+        forward(action: 'search', params: params)
+    }
+
+    /**
+    * Build and return the asset tree response for the AJAX request.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def assetTree = {
+        def s = assetTreeService.buildAssetTree(params, session)
+        render s
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def exportAssetTreeHtml = {
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=AssetTree.html")
+        def s = assetTreeService.buildAssetTree(params, session)
+        render s
+    }
+
+    /**
+    * Save the asset tree status in the current http session.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def saveAssetTreeStatus = {
+        session.assetTreeVisibleBranches = params.assetTreeVisibleBranches
+    }
+
+    /**
+    * Disaply the import view.
+    */
+    def importAssetTree = {
+    }
+
+    /**
+    * Handle the import save.
+    */
+    def importAssetTreeSave = {
+        def result = assetCsvService.importAssetTree(request)
+
+        if(!result.error) {
+            flash.message = g.message(code: "asset.tree.import.success")
+            redirect(action:search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: importAssetTree)
+    }
+
+    /**
+    * Export a csv template.
+    * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time!
+    * This does not appear to be a problem once deployed to Tomcat.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def exportAssetTreeTemplate = {
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=AssetTreeTemplate.csv")
+        def s = assetCsvService.buildAssetTreeTemplate()
+        render s
+    }
+
+    /**
+    * Export a csv test file.
+    */
+    def exportAssetTreeTest = {
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=AssetTreeTestFile.csv")
+        def s = assetCsvService.buildAssetTreeTest()
+        render s
+    }
+
+    /**
+    * Export the entire asset tree as a csv file.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def exportAssetTree = {
+
+        def assetList = Asset.list()
+
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=AssetTree.csv")
+        def s = assetCsvService.buildAssetTree(assetList)
+        render s
+    }
+
+    /**
+    * Search action.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def search = {
+
+        if(session.assetSearchParamsMax)
+            params.max = session.assetSearchParamsMax
+
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  1000)
+
+        def assetInstanceList = []
+        def assetInstanceTotal
+        def filterParams = [:]
+
+        // Quick Search:
+        if(!params.filter) {
+            assetInstanceList = Asset.list( params )
+            assetInstanceTotal = Asset.count()
+            filterParams.quickSearch = params.quickSearch
+        }
+        else {
+        // filterPane:
+            assetInstanceList = filterService.filter( params, Asset )
+            assetInstanceTotal = filterService.count( params, Asset )
+            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+        }
+
+        // export plugin:
+        if(params?.format && params.format != "html") {
+
+            def dateFmt = { date ->
+                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
+            }
+
+//             def fmtAsset = { m ->
+//                     def r = ''
+//                     def assetInstance = Asset.findByName(m)
+// 
+//                     r +=  assetInstance
+//                     r += ", "
+// 
+//                     def  lastSubAsset = assetInstance.subAssets.size() - 1
+//                     assetInstance.subAssets.eachWithIndex() { obj, i ->
+//                         r += "\"" + obj + "\""
+//                         if( i < lastSubAsset )
+//                             r += ", "
+//                     }
+//                     return r
+//             }
+
+//             def fmtSubAsset = { m ->
+//                     def r = ''
+//                     m.each() {
+//                         def machine = Machine.findByName(it)
+//                         def assemblies = machine.assemblies
+//                         r += machine.name
+//                         r += " "
+//                         r += assemblies
+//                         r += " "
+//                     }
+//                     return r
+//             }
+
+            String title = "Asset List."
+
+            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
+            response.setHeader("Content-disposition", "attachment; filename=Assets.${params.extension}")
+            List fields = ["section.site",
+                                "section",
+                                "name",
+                                "description"]
+            Map labels = ["section.site": "Site",
+                                "section": "Section",
+                                "name": "Asset",
+                                "description": "Description"]
+//             Map labels
+//             Map formatters = ["subAsset.name": fmtSubAsset]
+            Map formatters = [:]
+            Map parameters = [title: title, separator: ","]
+
+            exportService.export(params.format,
+                                                response.outputStream,
+                                                assetInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) },
+                                                fields,
+                                                labels,
+                                                formatters,
+                                                parameters)
+        }
+
+        // Add some basic params to filterParams.
+        filterParams.max = params.max
+        filterParams.offset = params.offset?.toInteger() ?: 0
+        filterParams.sort = params.sort ?: "id"
+        filterParams.order = params.order ?: "desc"
+
+        return[ assetInstanceList: assetInstanceList,
+                assetInstanceTotal: assetInstanceTotal,
+                filterParams: filterParams ]
+
+    } // end search()
+
+    /**
+    * Show action.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def assetInstance = Asset.get( params.id )
+
+        if(!assetInstance) {
+            flash.message = "Asset not found with id ${params.id}"
+            redirect(action:search)
+            return
+        }
+
+        return [ assetInstance : assetInstance,
+                        parentPMs: taskService.getParentPMs(assetInstance)]
+    }
+
+    /**
+    * Delete action.
+    */
+    def delete = {
+        def result = assetService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["Asset", params.id])
+            redirect(action:search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(action:search)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    /**
+    * Edit action.
+    */
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def assetInstance = Asset.get( params.id )
+
+        if(!assetInstance) {
+            flash.message = "Asset not found with id ${params.id}"
+            redirect(action:search)
+            return
+        }
+
+        return [ assetInstance : assetInstance,
+                        possibleAssetSubItems: assetService.possibleAssetSubItems(),
+                        parentPMs: taskService.getParentPMs(assetInstance) ]
+
+    }
+
+    /**
+    * Update action.
+    */
+    def update = {
+        def assetInstance = Asset.get( params.id )
+
+        if(!assetInstance) {
+            flash.message = "Asset not found with id ${params.id}"
+            redirect(action:search)
+            return
+        }
+
+        if(params.version) {
+            def version = params.version.toLong()
+            if(assetInstance.version > version) {
+
+                assetInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                render(view:'edit',model:[assetInstance:assetInstance,
+                                                            possibleAssetSubItems: assetService.possibleAssetSubItems(),
+                                                            parentPMs: taskService.getParentPMs(assetInstance)] )
+                return
+            }
+        }
+
+        assetInstance.properties = params
+
+        use(WordUtils) {
+            assetInstance.name = assetInstance.name.capitalize()
+            assetInstance.description = assetInstance.description.capitalize()
+        }
+
+        assetInstance.setAssetSubItemsFromCheckBoxList(params.assetSubItems)
+
+        if(!assetInstance.hasErrors() && assetInstance.save(flush: true)) {
+            flash.message = "Asset '${assetInstance.name}' updated"
+            redirect(action:show,id:assetInstance.id)
+        }
+        else {
+            render(view:'edit',model:[assetInstance:assetInstance,
+                                                        possibleAssetSubItems: assetService.possibleAssetSubItems(),
+                                                        parentPMs: taskService.getParentPMs(assetInstance)] )
+        }
+
+    }
+
+    /**
+    * Create action.
+    */
+    def create = {
+        def result = assetService.create(params)
+
+        if(!result.error)
+            return [assetInstance: result.assetInstance]
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: search)
+    }
+
+    /**
+    * Copy action.
+    */
+    def copy = {
+        def result = assetService.copy(params)
+
+        if(!result.error)
+            return [assetInstance: result.assetInstance, assetToCopy: result.assetToCopy]
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: search)
+    }
+
+    /**
+    * Save action.
+    */
+    def save = {
+        def result = assetService.save(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["Asset",  "'${result.assetInstance.name}'"])
+            redirect(action:show, id: result.assetInstance.id)
+            return
+        }
+
+        render(view:'create', model:[assetInstance: result.assetInstance])
+    }
+
+    /**
+    * Copy save action.
+    */
+    def saveCopy = {
+        def result = assetService.saveCopy(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["Asset", result.assetInstance.id])
+            redirect(action:show, id: result.assetInstance.id)
+            return
+        }
+
+        if(result.error.code == "default.not.found") {
+            flash.message = g.message(code: result.error.code, args: ["Asset", params.assetToCopy?.id])
+            redirect(action: search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: ["Asset"])
+
+        render(view:'copy', model:[assetInstance: result.assetInstance, assetToCopy: result.assetToCopy])
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/controllers/AssetExtendedAttributeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AssetExtendedAttributeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AssetExtendedAttributeDetailedController.groovy	(revision 875)
@@ -0,0 +1,97 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class AssetExtendedAttributeDetailedController extends BaseController {
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def index = { redirect(controller: "assetDetailed", action: "search", params:params) }
+
+    def show = {
+        def assetExtendedAttributeInstance = AssetExtendedAttribute.get( params.id )
+
+        if(!assetExtendedAttributeInstance) {
+            flash.message = "AssetExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+        else { return [ assetExtendedAttributeInstance : assetExtendedAttributeInstance ] }
+    }
+
+    def delete = {
+        def assetExtendedAttributeInstance = AssetExtendedAttribute.get( params.id )
+        if(assetExtendedAttributeInstance) {
+            def asset = assetExtendedAttributeInstance.asset
+            try {
+                assetExtendedAttributeInstance.delete(flush:true)
+                flash.message = "AssetExtendedAttribute ${params.id} deleted"
+                redirect(controller: "assetDetailed", action: 'show', id: asset.id)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "AssetExtendedAttribute ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "AssetExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+    }
+
+    def edit = {
+        def assetExtendedAttributeInstance = AssetExtendedAttribute.get( params.id )
+
+        if(!assetExtendedAttributeInstance) {
+            flash.message = "AssetExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+        else {
+            return [ assetExtendedAttributeInstance : assetExtendedAttributeInstance ]
+        }
+    }
+
+    def update = {
+        def assetExtendedAttributeInstance = AssetExtendedAttribute.get( params.id )
+        if(assetExtendedAttributeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(assetExtendedAttributeInstance.version > version) {
+                    
+                    assetExtendedAttributeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[assetExtendedAttributeInstance:assetExtendedAttributeInstance])
+                    return
+                }
+            }
+            assetExtendedAttributeInstance.properties = params
+            if(!assetExtendedAttributeInstance.hasErrors() && assetExtendedAttributeInstance.save(flush: true)) {
+                flash.message = "AssetExtendedAttribute ${params.id} updated"
+                //redirect(action:show,id:assetExtendedAttributeInstance.id)
+                redirect(controller: 'assetDetailed', action: 'show', id: assetExtendedAttributeInstance.asset.id)
+            }
+            else {
+                render(view:'edit',model:[assetExtendedAttributeInstance:assetExtendedAttributeInstance])
+            }
+        }
+        else {
+            flash.message = "AssetExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+    }
+
+    def create = {
+        def assetExtendedAttributeInstance = new AssetExtendedAttribute()
+        assetExtendedAttributeInstance.properties = params
+        return ['assetExtendedAttributeInstance':assetExtendedAttributeInstance]
+    }
+
+    def save = {
+        def assetExtendedAttributeInstance = new AssetExtendedAttribute(params)
+        if(!assetExtendedAttributeInstance.hasErrors() && assetExtendedAttributeInstance.save(flush: true)) {
+            flash.message = "AssetExtendedAttribute ${assetExtendedAttributeInstance.id} created"
+            redirect(controller:'assetDetailed', action:'edit',id:assetExtendedAttributeInstance.asset.id)
+        }
+        else {
+            render(view:'create',model:[assetExtendedAttributeInstance:assetExtendedAttributeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/AssetSubItemDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AssetSubItemDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AssetSubItemDetailedController.groovy	(revision 875)
@@ -0,0 +1,237 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import org.apache.commons.lang.WordUtils
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class AssetSubItemDetailedController extends BaseController {
+
+    def filterService
+    def exportService
+    def assetSubItemService
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def index = { redirect(action:search,params:params) }
+
+    /**
+    * Set session.assetSubItemSearchParamsMax
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def setSearchParamsMax = {
+        def max = 1000
+        if(params.newMax?.isInteger()) {
+            def i = params.newMax.toInteger()
+            if(i > 0 && i <= max)
+                session.assetSubItemSearchParamsMax = params.newMax
+            if(i > max)
+                session.assetSubItemSearchParamsMax = max
+        }
+        forward(action: 'search', params: params)
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def search = {
+
+        if(session.assetSubItemSearchParamsMax)
+            params.max = session.assetSubItemSearchParamsMax
+
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  1000)
+
+        def assetSubItemInstanceList = []
+        def assetSubItemInstanceTotal
+        def filterParams = [:]
+
+        // Quick Search:
+        if(!params.filter) {
+            assetSubItemInstanceList = AssetSubItem.list( params )
+            assetSubItemInstanceTotal = AssetSubItem.count()
+            filterParams.quickSearch = params.quickSearch
+        }
+        else {
+        // filterPane:
+            assetSubItemInstanceList = filterService.filter( params, AssetSubItem )
+            assetSubItemInstanceTotal = filterService.count( params, AssetSubItem )
+            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+        }
+
+        // export plugin:
+        if(params?.format && params.format != "html") {
+
+            def dateFmt = { date ->
+                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
+            }
+
+            String title = "AssetSubItem List."
+
+            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
+            response.setHeader("Content-disposition", "attachment; filename=assets.${params.extension}")
+            List fields = ["name",
+                                "description"]
+            Map labels = ["name": "AssetSubItem",
+                                "description": "Description"]
+
+            Map formatters = [:]
+            Map parameters = [title: title, separator: ","]
+
+            exportService.export(params.format,
+                                                response.outputStream,
+                                                assetSubItemInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) },
+                                                fields,
+                                                labels,
+                                                formatters,
+                                                parameters)
+        }
+
+        // Add some basic params to filterParams.
+        filterParams.max = params.max
+        filterParams.offset = params.offset?.toInteger() ?: 0
+        filterParams.sort = params.sort ?: "id"
+        filterParams.order = params.order ?: "desc"
+
+        return[ assetSubItemInstanceList: assetSubItemInstanceList,
+                assetSubItemInstanceTotal: assetSubItemInstanceTotal,
+                filterParams: filterParams ]
+
+    } // end search()
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def assetSubItemInstance = AssetSubItem.get( params.id )
+
+        if(!assetSubItemInstance) {
+            flash.message = "AssetSubItem not found with id ${params.id}"
+            redirect(action: "search")
+        }
+        else { return [ assetSubItemInstance : assetSubItemInstance ] }
+    }
+
+    def delete = {
+        def result = assetSubItemService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["AssetSubItem", params.id])
+            redirect(action: search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(action: search)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def assetSubItemInstance = AssetSubItem.get( params.id )
+
+        if(!assetSubItemInstance) {
+            flash.message = "AssetSubItem not found with id ${params.id}"
+            redirect(action: "search")
+            return
+        }
+
+        def possibleParentItems = assetSubItemService.possibleParentItems(assetSubItemInstance)
+
+        return [ assetSubItemInstance : assetSubItemInstance, possibleParentItems: possibleParentItems ]
+    }
+
+    def update = {
+        def assetSubItemInstance = AssetSubItem.get( params.id )
+        if(assetSubItemInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(assetSubItemInstance.version > version) {
+
+                    assetSubItemInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[assetSubItemInstance:assetSubItemInstance])
+                    return
+                }
+            }
+
+            assetSubItemInstance.properties = params
+
+            use(WordUtils) {
+                assetSubItemInstance.name = assetSubItemInstance.name.capitalize()
+                assetSubItemInstance.description = assetSubItemInstance.description.capitalize()
+            }
+
+            if(assetSubItemInstance.assets) {
+                assetSubItemInstance.parentItem = null
+            }
+
+            if(!assetSubItemInstance.hasErrors() && assetSubItemInstance.save(flush: true)) {
+                flash.message = "Sub Item '${assetSubItemInstance.name}' updated"
+                redirect(action:"show", id: assetSubItemInstance.id)
+            }
+            else {
+                render(view:'edit',model:[assetSubItemInstance:assetSubItemInstance])
+            }
+        }
+        else {
+            flash.message = "AssetSubItem not found with id ${params.id}"
+            redirect(action: "search")
+        }
+    } // update
+
+    def create = {
+        def result = assetSubItemService.create(params)
+
+        if(!result.error)
+            return [assetSubItemInstance: result.assetSubItemInstance, assetInstance: result.assetInstance]
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+        redirect(controller: 'assetDetailed', action: 'search')
+    }
+
+    def save = {
+        def result = assetSubItemService.save(params)
+
+        if(!result.error) {
+            // Success.
+            flash.message = g.message(code: "default.create.success", args: ["Sub Item", "'${result.assetSubItemInstance.name}'"])
+
+            /// @todo: This just grabs the first parent in an unsorted list and needs improving.
+            if(result.assetSubItemInstance.assets)
+                redirect(controller: "assetDetailed", action:"show", id: result.assetSubItemInstance.assets.toArray()[0].id)
+            else {
+                //Get the top parentItem.
+                def parentItem = result.assetSubItemInstance.parentItem
+                def i = 0
+                while(parentItem?.parentItem) {
+                    parentItem = parentItem.parentItem
+                    // Protect against infinite recurrsion.
+                    i++
+                    if(i > 100)
+                        break
+                }
+
+                if(parentItem?.assets)
+                    redirect(controller: "assetDetailed", action:"show", id: parentItem.assets.toArray()[0].id)
+                else
+                    redirect(action:"show", id: result.assetSubItemInstance.id) // End stop if all else fails.
+            }
+            return
+        }
+
+        if(result.error.code == "assetSubItem.asset.not.found")
+            flash.errorMessage = g.message(code: "default.create.success")
+
+        render(view:'create', model:[assetSubItemInstance: result.assetSubItemInstance, assetInstance: result.assetInstance])
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/controllers/AssetSubItemExtendedAttributeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AssetSubItemExtendedAttributeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AssetSubItemExtendedAttributeDetailedController.groovy	(revision 875)
@@ -0,0 +1,97 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class AssetSubItemExtendedAttributeDetailedController extends BaseController {
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def index = { redirect(controller: "assetDetailed", action: "search", params:params) }
+
+    def show = {
+        def assetSubItemExtendedAttributeInstance = AssetSubItemExtendedAttribute.get( params.id )
+
+        if(!assetSubItemExtendedAttributeInstance) {
+            flash.message = "AssetSubItemExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+        else { return [ assetSubItemExtendedAttributeInstance : assetSubItemExtendedAttributeInstance ] }
+    }
+
+    def delete = {
+        def assetSubItemExtendedAttributeInstance = AssetSubItemExtendedAttribute.get( params.id )
+        if(assetSubItemExtendedAttributeInstance) {
+            def assetSubItem = assetSubItemExtendedAttributeInstance.assetSubItem
+            try {
+                assetSubItemExtendedAttributeInstance.delete(flush:true)
+                flash.message = "AssetSubItemExtendedAttribute ${params.id} deleted"
+                redirect(controller: "assetSubItemDetailed", action: 'show', id: assetSubItem.id)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "AssetSubItemExtendedAttribute ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "AssetSubItemExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+    }
+
+    def edit = {
+        def assetSubItemExtendedAttributeInstance = AssetSubItemExtendedAttribute.get( params.id )
+
+        if(!assetSubItemExtendedAttributeInstance) {
+            flash.message = "AssetSubItemExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+        else {
+            return [ assetSubItemExtendedAttributeInstance : assetSubItemExtendedAttributeInstance ]
+        }
+    }
+
+    def update = {
+        def assetSubItemExtendedAttributeInstance = AssetSubItemExtendedAttribute.get( params.id )
+        if(assetSubItemExtendedAttributeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(assetSubItemExtendedAttributeInstance.version > version) {
+                    
+                    assetSubItemExtendedAttributeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[assetSubItemExtendedAttributeInstance:assetSubItemExtendedAttributeInstance])
+                    return
+                }
+            }
+            assetSubItemExtendedAttributeInstance.properties = params
+            if(!assetSubItemExtendedAttributeInstance.hasErrors() && assetSubItemExtendedAttributeInstance.save(flush: true)) {
+                flash.message = "AssetSubItemExtendedAttribute ${params.id} updated"
+                //redirect(action:show,id:assetSubItemExtendedAttributeInstance.id)
+                redirect(controller: 'assetSubItemDetailed', action: 'show', id: assetSubItemExtendedAttributeInstance.assetSubItem.id)
+            }
+            else {
+                render(view:'edit',model:[assetSubItemExtendedAttributeInstance:assetSubItemExtendedAttributeInstance])
+            }
+        }
+        else {
+            flash.message = "AssetSubItemExtendedAttribute not found with id ${params.id}"
+            redirect(controller: "assetDetailed", action: "search")
+        }
+    }
+
+    def create = {
+        def assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute()
+        assetSubItemExtendedAttributeInstance.properties = params
+        return ['assetSubItemExtendedAttributeInstance':assetSubItemExtendedAttributeInstance]
+    }
+
+    def save = {
+        def assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(params)
+        if(!assetSubItemExtendedAttributeInstance.hasErrors() && assetSubItemExtendedAttributeInstance.save(flush: true)) {
+            flash.message = "AssetSubItemExtendedAttribute ${assetSubItemExtendedAttributeInstance.id} created"
+            redirect(controller:'assetSubItemDetailed', action:'edit',id:assetSubItemExtendedAttributeInstance.assetSubItem.id)
+        }
+        else {
+            render(view:'create',model:[assetSubItemExtendedAttributeInstance:assetSubItemExtendedAttributeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/AssignedGroupDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AssignedGroupDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AssignedGroupDetailedController.groovy	(revision 875)
@@ -0,0 +1,130 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+class AssignedGroupDetailedController extends BaseController {
+
+    def assignedGroupService
+
+    def index = {
+        flash.message = g.message(code: "assignedGroup.task.not.found")
+        redirect(controller:"taskDetailed", action:"search")
+    }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def delete = {
+        def result = assignedGroupService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["AssignedGroup", params.id])
+            redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+            return
+        }
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+        def result = assignedGroupService.edit(params)
+
+        if(!result.error) {
+            return [assignedGroupInstance: result.assignedGroupInstance,
+                            personGroup: result.personGroup,
+                            personsInGroup: result.personsInGroup]
+        }
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+
+        redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+
+    }
+
+    def update = {
+        def result = assignedGroupService.update(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.update.success", args: ["AssignedGroup", params.id])
+            redirect(controller:"taskDetailed", action:"show", id: result.assignedGroupInstance.task.id)
+            return
+        }
+
+        if(result.error.code == "default.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+            return
+        }
+
+        if(result.error.code == "personGroup.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(action:"edit", id: params.id)
+            return
+        }
+
+        render(view:'edit', model:[assignedGroupInstance: result.assignedGroupInstance.attach(),
+                                                personGroup: result.personGroup.attach(),
+                                                personsInGroup: result.personsInGroup])
+    }
+
+    def create = {
+        def result = assignedGroupService.create(params)
+
+        if(!result.error) {
+            return [assignedGroupInstance: result.assignedGroupInstance,
+                            personGroup: result.personGroup,
+                            personsInGroup: result.personsInGroup]
+        }
+
+        if(result.error.code == "assignedGroup.task.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(controller: "taskDetailed", action: "search")
+            return
+        }
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+        redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+    }
+
+    def save = {
+        def result = assignedGroupService.save(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["AssignedGroup", result.assignedGroupInstance.id])
+            redirect(controller:"taskDetailed", action:"show", id: result.assignedGroupInstance.task.id)
+            return
+        }
+
+        if(result.error.code == "personGroup.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(action:"create", params:["task.id": params.task?.id])
+            return
+        }
+
+        render(view:'create', model:[assignedGroupInstance: result.assignedGroupInstance,
+                                                personGroup: result.personGroup.attach(),
+                                                personsInGroup: result.personsInGroup])
+    }
+
+    def personsInGroup = {
+        def result = assignedGroupService.personsInGroup(params)
+
+        if(!result.error) {
+            render ( template:"personsInGroup",
+                            model: [personGroup: result.personGroup, personsInGroup: result.personsInGroup] )
+            return
+        }
+
+        render {
+            div(id:"personsInGroup", g.message(code: result.error.code, args: result.error.args) )
+        }
+
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/AssignedPersonDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AssignedPersonDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AssignedPersonDetailedController.groovy	(revision 875)
@@ -0,0 +1,130 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+class AssignedPersonDetailedController extends BaseController {
+
+    def assignedPersonService
+
+    def index = {
+        flash.message = g.message(code: "assignedPerson.task.not.found")
+        redirect(controller:"taskDetailed", action:"search")
+    }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def delete = {
+        def result = assignedPersonService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["AssignedPerson", params.id])
+            redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+            return
+        }
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+        def result = assignedPersonService.edit(params)
+
+        if(!result.error) {
+            return [assignedPersonInstance: result.assignedPersonInstance,
+                            person: result.person,
+                            groupsForPerson: result.groupsForPerson]
+        }
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+
+        redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+
+    }
+
+    def update = {
+        def result = assignedPersonService.update(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.update.success", args: ["AssignedPerson", params.id])
+            redirect(controller:"taskDetailed", action:"show", id: result.assignedPersonInstance.task.id)
+            return
+        }
+
+        if(result.error.code == "default.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+            return
+        }
+
+        if(result.error.code == "person.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(action:"edit", id: params.id)
+            return
+        }
+
+        render(view:'edit', model:[assignedPersonInstance: result.assignedPersonInstance.attach(),
+                                                person: result.person.attach(),
+                                                groupsForPerson: result.groupsForPerson])
+    }
+
+    def create = {
+        def result = assignedPersonService.create(params)
+
+        if(!result.error) {
+            return [assignedPersonInstance: result.assignedPersonInstance,
+                            person: result.person,
+                            groupsForPerson: result.groupsForPerson]
+        }
+
+        if(result.error.code == "assignedPerson.task.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(controller: "taskDetailed", action: "search")
+            return
+        }
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+        redirect(controller:"taskDetailed", action:"show", id: params.task?.id)
+    }
+
+    def save = {
+        def result = assignedPersonService.save(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["AssignedPerson", result.assignedPersonInstance.id])
+            redirect(controller:"taskDetailed", action:"show", id: result.assignedPersonInstance.task.id)
+            return
+        }
+
+        if(result.error.code == "person.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(action:"create", params:["task.id": params.task?.id])
+            return
+        }
+
+        render(view:'create', model:[assignedPersonInstance: result.assignedPersonInstance,
+                                                person: result.person.attach(),
+                                                groupsForPerson: result.groupsForPerson])
+    }
+
+    def groupsForPerson = {
+        def result = assignedPersonService.groupsForPerson(params)
+
+        if(!result.error) {
+            render ( template:"groupsForPerson",
+                            model: [person: result.person, groupsForPerson: result.groupsForPerson] )
+            return
+        }
+
+        render {
+            div(id:"groupsForPerson", g.message(code: result.error.code, args: result.error.args) )
+        }
+
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/AuthorityController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/AuthorityController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/AuthorityController.groovy	(revision 875)
@@ -0,0 +1,118 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class AuthorityController extends BaseAppAdminController {
+
+    // the delete, save and update actions only accept POST requests
+    static Map allowedMethods = [delete: 'POST', save: 'POST', update: 'POST']
+
+    def authenticateService
+
+    def index = {
+        redirect action: list, params: params
+    }
+
+    /**
+    * Display the list authority page.
+    */
+    def list = {
+        if (!params.max) {
+            params.max = 10
+        }
+        [authorityList: Authority.list(params)]
+    }
+
+    /**
+    * Display the show authority page.
+    */
+    def show = {
+        def authority = Authority.get(params.id)
+        if (!authority) {
+            flash.message = "Authority not found with id $params.id"
+            redirect action: list
+            return
+        }
+
+        [authority: authority]
+    }
+
+    /**
+    * Delete an authority.
+    */
+    def delete = {
+        def authority = Authority.get(params.id)
+        if (!authority) {
+            flash.message = "Authority not found with id $params.id"
+            redirect action: list
+            return
+        }
+
+        authenticateService.deleteRole(authority)
+
+        flash.message = "Authority $params.id deleted."
+        redirect action: list
+    }
+
+    /**
+    * Display the edit authority page.
+    */
+    def edit = {
+        def authority = Authority.get(params.id)
+        if (!authority) {
+            flash.message = "Authority not found with id $params.id"
+            redirect action: list
+            return
+        }
+
+        [authority: authority]
+    }
+
+    /**
+    * Authority update action.
+    */
+    def update = {
+
+        def authority = Authority.get(params.id)
+        if (!authority) {
+            flash.message = "Authority not found with id $params.id"
+            redirect action: edit, id: params.id
+            return
+        }
+
+        long version = params.version.toLong()
+        if (authority.version > version) {
+            authority.errors.rejectValue 'version', "default.optimistic.locking.failure"
+            render view: 'edit', model: [authority: authority]
+            return
+        }
+
+        if (authenticateService.updateRole(authority, params)) {
+            authenticateService.clearCachedRequestmaps()
+            redirect action: show, id: authority.id
+        }
+        else {
+            render view: 'edit', model: [authority: authority]
+        }
+    }
+
+    /**
+    * Display the create new authority page.
+    */
+    def create = {
+        [authority: new Authority()]
+    }
+
+    /**
+    * Save a new authority.
+    */
+    def save = {
+
+        def authority = new Authority()
+        authority.properties = params
+        if (authority.save(flush: true)) {
+            redirect action: show, id: authority.id
+        }
+        else {
+            render view: 'create', model: [authority: authority]
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/BaseAppAdminController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/BaseAppAdminController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/BaseAppAdminController.groovy	(revision 875)
@@ -0,0 +1,7 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin'])
+abstract class BaseAppAdminController {
+
+}
+
Index: /branches/features/grailsUpgrade/grails-app/controllers/BaseController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/BaseController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/BaseController.groovy	(revision 875)
@@ -0,0 +1,7 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AppUser'])
+abstract class BaseController {
+
+}
+
Index: /branches/features/grailsUpgrade/grails-app/controllers/ContactDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/ContactDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/ContactDetailedController.groovy	(revision 875)
@@ -0,0 +1,129 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                    'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager'])
+class ContactDetailedController extends BaseController {
+
+    def contactService
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager', 'ROLE_AppUser'])
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager', 'ROLE_AppUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ contactInstanceList: Contact.list( params ), contactInstanceTotal: Contact.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager',
+                        'ROLE_InventoryManager', 'ROLE_AssetManager', 'ROLE_ProductionManager', 'ROLE_AppUser'])
+    def show = {
+        def contactInstance = Contact.get( params.id )
+
+        if(!contactInstance) {
+            flash.message = "Contact not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ contactInstance : contactInstance ] }
+    }
+
+    def delete = {
+        def result = contactService.delete(params)
+
+        if(!result.error) {
+            if(result.ownerInstance) {
+                def c = getControllerName(result.ownerInstance)
+                flash.message = g.message(code: "default.delete.success", args: ["Contact", ''])
+                redirect(controller:c, action:'edit', id: result.ownerInstance.id)
+                return
+            }
+            flash.message = g.message(code: "default.delete.success", args: ["Contact", params.id])
+            redirect(action:list)
+            return
+        }
+
+        flash.message = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(action:list)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+        def contactInstance = Contact.get( params.id )
+
+        if(!contactInstance) {
+            flash.message = "Contact not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ contactInstance : contactInstance ]
+        }
+    }
+
+    def update = {
+        def contactInstance = Contact.get( params.id )
+        if(contactInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(contactInstance.version > version) {
+
+                    contactInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[contactInstance:contactInstance])
+                    return
+                }
+            }
+            contactInstance.properties = params
+            if(!contactInstance.hasErrors() && contactInstance.save(flush: true)) {
+                flash.message = "Contact ${params.id} updated"
+                redirect(action:show,id:contactInstance.id)
+            }
+            else {
+                render(view:'edit',model:[contactInstance:contactInstance])
+            }
+        }
+        else {
+            flash.message = "Contact not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def result = contactService.create(params)
+
+        if(!result.error)
+            return [contactInstance: result.contactInstance]
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: list)
+    }
+
+    def save = {
+        def result = contactService.save(params)
+
+        if(!result.error) {
+            def c = getControllerName(result.ownerInstance)
+            flash.message = g.message(code: "default.create.success", args: ["Contact", ''])
+            redirect(controller:c, action:'edit', id: result.ownerInstance.id)
+            return
+        }
+
+        render(view:'create', model:[contactInstance: result.contactInstance])
+    }
+
+    private getControllerName(ownerInstance) {
+        if(ownerInstance.class.name == 'Person')
+            return "${ownerInstance.class.name[0].toLowerCase() + ownerInstance.class.name[1..-1]}"
+        else
+            return "${ownerInstance.class.name[0].toLowerCase() + ownerInstance.class.name[1..-1]}"+"Detailed"
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/CostCodeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/CostCodeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/CostCodeDetailedController.groovy	(revision 875)
@@ -0,0 +1,115 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class CostCodeDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ costCodeInstanceList: CostCode.list( params ), costCodeInstanceTotal: CostCode.count() ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def costCodeInstance = CostCode.get( params.id )
+
+        if(!costCodeInstance) {
+            flash.message = "CostCode not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ costCodeInstance : costCodeInstance ] }
+    }
+
+    def delete = {
+        def costCodeInstance = CostCode.get( params.id )
+        if(costCodeInstance) {
+            try {
+                costCodeInstance.delete(flush:true)
+                flash.message = "CostCode ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "CostCode ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "CostCode not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def costCodeInstance = CostCode.get( params.id )
+
+        if(!costCodeInstance) {
+            flash.message = "CostCode not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ costCodeInstance : costCodeInstance ]
+        }
+    }
+
+    def update = {
+        def costCodeInstance = CostCode.get( params.id )
+        if(costCodeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(costCodeInstance.version > version) {
+
+                    costCodeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[costCodeInstance:costCodeInstance])
+                    return
+                }
+            }
+            costCodeInstance.properties = params
+            // Trim name to avoid spaces.
+            costCodeInstance.name = costCodeInstance.name.trim()
+            if(!costCodeInstance.hasErrors() && costCodeInstance.save(flush: true)) {
+                flash.message = "CostCode ${params.id} updated"
+                redirect(action:show,id:costCodeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[costCodeInstance:costCodeInstance])
+            }
+        }
+        else {
+            flash.message = "CostCode not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def costCodeInstance = new CostCode()
+        costCodeInstance.properties = params
+        return ['costCodeInstance':costCodeInstance]
+    }
+
+    def save = {
+        def costCodeInstance = new CostCode(params)
+        // Trim name to avoid spaces.
+        costCodeInstance.name = costCodeInstance.name.trim()
+        if(!costCodeInstance.hasErrors() && costCodeInstance.save(flush: true)) {
+            flash.message = "CostCode ${costCodeInstance.id} created"
+            redirect(action:show,id:costCodeInstance.id)
+        }
+        else {
+            render(view:'create',model:[costCodeInstance:costCodeInstance])
+        }
+    } // save
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/controllers/DepartmentDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/DepartmentDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/DepartmentDetailedController.groovy	(revision 875)
@@ -0,0 +1,100 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class DepartmentDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ departmentInstanceList: Department.list( params ), departmentInstanceTotal: Department.count() ]
+    }
+
+    def show = {
+        def departmentInstance = Department.get( params.id )
+
+        if(!departmentInstance) {
+            flash.message = "Department not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ departmentInstance : departmentInstance ] }
+    }
+
+    def delete = {
+        def departmentInstance = Department.get( params.id )
+        if(departmentInstance) {
+            try {
+                departmentInstance.delete(flush:true)
+                flash.message = "Department ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "Department ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "Department not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def departmentInstance = Department.get( params.id )
+
+        if(!departmentInstance) {
+            flash.message = "Department not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ departmentInstance : departmentInstance ]
+        }
+    }
+
+    def update = {
+        def departmentInstance = Department.get( params.id )
+        if(departmentInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(departmentInstance.version > version) {
+                    
+                    departmentInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[departmentInstance:departmentInstance])
+                    return
+                }
+            }
+            departmentInstance.properties = params
+            if(!departmentInstance.hasErrors() && departmentInstance.save(flush: true)) {
+                flash.message = "Department ${params.id} updated"
+                redirect(action:show,id:departmentInstance.id)
+            }
+            else {
+                render(view:'edit',model:[departmentInstance:departmentInstance])
+            }
+        }
+        else {
+            flash.message = "Department not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def departmentInstance = new Department()
+        departmentInstance.properties = params
+        return ['departmentInstance':departmentInstance]
+    }
+
+    def save = {
+        def departmentInstance = new Department(params)
+        if(!departmentInstance.hasErrors() && departmentInstance.save(flush: true)) {
+            flash.message = "Department ${departmentInstance.id} created"
+            redirect(action:show,id:departmentInstance.id)
+        }
+        else {
+            render(view:'create',model:[departmentInstance:departmentInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/DepartmentExtendedAttributeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/DepartmentExtendedAttributeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/DepartmentExtendedAttributeDetailedController.groovy	(revision 875)
@@ -0,0 +1,100 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class DepartmentExtendedAttributeDetailedController extends BaseController {
+
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ departmentExtendedAttributeInstanceList: DepartmentExtendedAttribute.list( params ), departmentExtendedAttributeInstanceTotal: DepartmentExtendedAttribute.count() ]
+    }
+
+    def show = {
+        def departmentExtendedAttributeInstance = DepartmentExtendedAttribute.get( params.id )
+
+        if(!departmentExtendedAttributeInstance) {
+            flash.message = "DepartmentExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ departmentExtendedAttributeInstance : departmentExtendedAttributeInstance ] }
+    }
+
+    def delete = {
+        def departmentExtendedAttributeInstance = DepartmentExtendedAttribute.get( params.id )
+        if(departmentExtendedAttributeInstance) {
+            try {
+                departmentExtendedAttributeInstance.delete(flush:true)
+                flash.message = "DepartmentExtendedAttribute ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "DepartmentExtendedAttribute ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "DepartmentExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def departmentExtendedAttributeInstance = DepartmentExtendedAttribute.get( params.id )
+
+        if(!departmentExtendedAttributeInstance) {
+            flash.message = "DepartmentExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ departmentExtendedAttributeInstance : departmentExtendedAttributeInstance ]
+        }
+    }
+
+    def update = {
+        def departmentExtendedAttributeInstance = DepartmentExtendedAttribute.get( params.id )
+        if(departmentExtendedAttributeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(departmentExtendedAttributeInstance.version > version) {
+                    
+                    departmentExtendedAttributeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[departmentExtendedAttributeInstance:departmentExtendedAttributeInstance])
+                    return
+                }
+            }
+            departmentExtendedAttributeInstance.properties = params
+            if(!departmentExtendedAttributeInstance.hasErrors() && departmentExtendedAttributeInstance.save(flush: true)) {
+                flash.message = "DepartmentExtendedAttribute ${params.id} updated"
+                redirect(action:show,id:departmentExtendedAttributeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[departmentExtendedAttributeInstance:departmentExtendedAttributeInstance])
+            }
+        }
+        else {
+            flash.message = "DepartmentExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def departmentExtendedAttributeInstance = new DepartmentExtendedAttribute()
+        departmentExtendedAttributeInstance.properties = params
+        return ['departmentExtendedAttributeInstance':departmentExtendedAttributeInstance]
+    }
+
+    def save = {
+        def departmentExtendedAttributeInstance = new DepartmentExtendedAttribute(params)
+        if(!departmentExtendedAttributeInstance.hasErrors() && departmentExtendedAttributeInstance.save(flush: true)) {
+            flash.message = "DepartmentExtendedAttribute ${departmentExtendedAttributeInstance.id} created"
+            redirect(action:show,id:departmentExtendedAttributeInstance.id)
+        }
+        else {
+            render(view:'create',model:[departmentExtendedAttributeInstance:departmentExtendedAttributeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/EntryDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/EntryDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/EntryDetailedController.groovy	(revision 875)
@@ -0,0 +1,224 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+class EntryDetailedController extends BaseController {
+
+    def authService
+    def taskService
+
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST', ajaxCreate:'POST', ajaxSave:'POST']
+
+    def list = {
+        if(!params.max) params.max = 10
+        [ entryInstanceList: Entry.list( params ) ]
+    }
+
+    def show = {
+        def entryInstance = Entry.get( params.id )
+
+        if(!entryInstance) {
+            flash.message = "Entry not found with id ${params.id}"
+            redirect(controller: 'taskDetailed', action: 'search')
+        }
+        else { return [ entryInstance : entryInstance ] }
+    }
+
+    def delete = {
+        def entryInstance = Entry.get( params.id )
+        if(entryInstance) {
+            if(entryInstance.enteredBy.loginName == authService.currentUser.loginName) {
+                def taskId = entryInstance.task.id
+                entryInstance.delete(flush:true)
+                flash.message = "Entry ${params.id} deleted"
+                redirect(controller: 'taskDetailed', action: 'show', id: taskId)
+            }
+            else {
+                flash.message = "You may only delete your own entries."
+                redirect(action:show,id:entryInstance.id)
+            }
+
+        }
+        else {
+            flash.message = "Entry not found with id ${params.id}"
+            redirect(controller: "taskDetailed", action:"search")
+        }
+    }
+
+    def edit = {
+        def entryInstance = Entry.get( params.id )
+        if(!entryInstance) {
+                flash.message = "Entry not found with id ${params.id}"
+                redirect(controller: "taskDetailed", action:"search")
+        }
+        else {
+
+            if(entryInstance.enteredBy.loginName == authService.currentUser.loginName) {
+                return [ entryInstance : entryInstance ]
+            }
+            else {
+                flash.message = "You may only edit your own entries."
+                redirect(action:show,id:entryInstance.id)
+            }
+
+        }
+    }
+
+    /// @todo: Refactor to taskService and include moving task to "In Progress" when Entry.duration is updated.
+    def update = {
+        def entryInstance = Entry.get( params.id )
+        if(entryInstance) {
+            // The update method only accepts post requests, so this is just in case.
+            if(entryInstance.enteredBy.loginName == authService.currentUser.loginName) {
+                entryInstance.properties = params
+                if(!entryInstance.hasErrors() && entryInstance.save(flush: true)) {
+                    // If PM Entry update task.highestSeverity
+                    if(entryInstance.entryType.id == 6) {
+                        def clist = []
+                        entryInstance.task.entries.each { entry ->
+                            if(entry.entryType.id == 6)
+                                clist << entry.highestSeverity
+                        }
+
+                        if(clist)
+                            entryInstance.task.highestSeverity = clist.sort{p1,p2 -> p2.id <=> p1.id}[0]
+                    }
+                    flash.message = "Entry ${params.id} updated"
+                    redirect(action:show,id:entryInstance.id)
+                }
+                else {
+                    render(view:'edit',model:[entryInstance:entryInstance])
+                }
+            }
+            else {
+                flash.message = "You may only edit your own entries."
+                redirect(action:show,id:entryInstance.id)
+            }
+        }
+        else {
+            flash.message = "Entry not found with id ${params.id}"
+            redirect(controller: "taskDetailed", action:"search")
+        }
+    }
+
+    def ajaxCreate = {
+        if(!params.taskId || !params.entryTypeId) {
+            params.errorMessage = g.message(code: "entry.create.no.params.ajax")
+            render(contentType:"text/json", status: 403, template: "/shared/messages")
+            return
+        }
+
+        def taskInstance = Task.read(params.taskId)
+
+        def entryInstance = new Entry()
+        entryInstance.task = taskInstance
+        entryInstance.entryType = EntryType.read(params.entryTypeId)
+
+        // Check if we should create this entry.
+        def checkResult = taskService.checkCreateEntry(entryInstance)
+        if(checkResult.error) {
+            params.errorMessage = g.message(code: checkResult.error.code)
+            render(contentType:"text/json", status: 403, template: "/shared/messages")
+            return
+        }
+
+        // Success.
+        def model = ['entryInstance': entryInstance]
+
+        render(contentType:"text/json") {
+            updates = array {
+                element([ mode: 'replace', target:"$params.target", content: g.render(template: 'create', model:model) ])
+            }
+        }
+
+    } // ajaxCreate
+
+    def ajaxSave = {
+        def result = taskService.saveEntry(params)
+
+        // Success.
+        if(!result.error) {
+            def entryList = Entry.withCriteria {
+                                            eq("entryType", result.entryInstance.entryType)
+                                            task {
+                                                idEq(result.taskId)
+                                            }
+                                    }
+
+            def taskInstance = entryList[0].task
+            def taskModificationList = TaskModification.findAllByTask(taskInstance, [max:100, sort:"id", order:"asc"])
+            def model = ['entryList': entryList]
+            def taskModel = ['taskInstance': taskInstance]
+            def taskModificationModel = ['taskModificationList': taskModificationList ]
+
+            render(contentType:"text/json") {
+                updates = array {
+                    element([ mode: 'replace', target:"$params.target", content: g.render(template: 'list', model:model) ])
+                    element([ mode: 'replace',
+                                    target:".tabHeader",
+                                    content: g.render(template: '/taskDetailed/showTabHeader', model:taskModel) ])
+                    element([ mode: 'replace',
+                                    target:"#taskControlButtons",
+                                    content: g.render(template: '/taskDetailed/showTaskControlButtons', model:taskModel) ])
+                    element([ mode: 'replace',
+                                    target:"#modifications",
+                                    content: g.render(template: '/taskDetailed/showTaskModifications', model:taskModificationModel) ])
+                }
+            }
+            return
+        } // Success.
+
+        if(result.error.code != "default.create.failure")
+            params.errorMessage = g.message(code: result.error.code)
+
+        def model = ['entryInstance': result.entryInstance]
+        render(contentType:"text/json", status: 403, template: "create", model: model)
+    } // ajaxSave
+
+    def create = {
+        if(!params.taskInstance?.id || !params.entryType?.id) {
+            flash.message = g.message(code:"entry.create.no.params")
+            redirect(controller:"taskDetailed", action:"search")
+            return
+        }
+
+        def taskInstance = Task.read(params.taskInstance.id)
+
+        if(!taskInstance) {
+            flash.message = g.message(code:"task.notFound")
+            redirect(controller:"taskDetailed", action:"search")
+            return
+        }
+
+        // Check for Complete task.
+        if(taskInstance.taskStatus.id == 3) {
+            flash.errorMessage = g.message(code:"task.operationNotPermittedOnCompleteTask")
+            redirect(controller:"taskDetailed", action:"show", id: taskInstance.id)
+            return
+        }
+
+        def entryInstance = new Entry()
+        entryInstance.task = taskInstance
+        entryInstance.entryType = EntryType.read(params.entryType.id)
+        return ['entryInstance': entryInstance]
+    } // create
+
+    def save = {
+        def result = taskService.saveEntry(params)
+
+        if(!result.error) {
+            flash.message = "Entry created."
+            redirect(controller: "taskDetailed", action: "show", id: result.taskId)
+            return
+        }
+
+        if(result.error.code != "default.create.failure") {
+            params.errorMessage = g.message(code: result.error.code)
+        }
+
+        render(view:'create',model:[entryInstance: result.entryInstance])
+    } // save
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/controllers/EntryTypeController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/EntryTypeController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/EntryTypeController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class EntryTypeController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ entryTypeInstanceList: EntryType.list( params ), entryTypeInstanceTotal: EntryType.count() ]
+    }
+
+    def show = {
+        def entryTypeInstance = EntryType.get( params.id )
+
+        if(!entryTypeInstance) {
+            flash.message = "EntryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ entryTypeInstance : entryTypeInstance ] }
+    }
+
+    def delete = {
+        def entryTypeInstance = EntryType.get( params.id )
+        if(entryTypeInstance) {
+            try {
+                entryTypeInstance.delete(flush:true)
+                flash.message = "EntryType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "EntryType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "EntryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def entryTypeInstance = EntryType.get( params.id )
+
+        if(!entryTypeInstance) {
+            flash.message = "EntryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ entryTypeInstance : entryTypeInstance ]
+        }
+    }
+
+    def update = {
+        def entryTypeInstance = EntryType.get( params.id )
+        if(entryTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(entryTypeInstance.version > version) {
+                    
+                    entryTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[entryTypeInstance:entryTypeInstance])
+                    return
+                }
+            }
+            entryTypeInstance.properties = params
+            if(!entryTypeInstance.hasErrors() && entryTypeInstance.save(flush: true)) {
+                flash.message = "EntryType ${params.id} updated"
+                redirect(action:show,id:entryTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[entryTypeInstance:entryTypeInstance])
+            }
+        }
+        else {
+            flash.message = "EntryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def entryTypeInstance = new EntryType()
+        entryTypeInstance.properties = params
+        return ['entryTypeInstance':entryTypeInstance]
+    }
+
+    def save = {
+        def entryTypeInstance = new EntryType(params)
+        if(!entryTypeInstance.hasErrors() && entryTypeInstance.save(flush: true)) {
+            flash.message = "EntryType ${entryTypeInstance.id} created"
+            redirect(action:show,id:entryTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[entryTypeInstance:entryTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/ExtendedAttributeTypeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/ExtendedAttributeTypeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/ExtendedAttributeTypeDetailedController.groovy	(revision 875)
@@ -0,0 +1,110 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class ExtendedAttributeTypeDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ extendedAttributeTypeInstanceList: ExtendedAttributeType.list( params ), extendedAttributeTypeInstanceTotal: ExtendedAttributeType.count() ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def extendedAttributeTypeInstance = ExtendedAttributeType.get( params.id )
+
+        if(!extendedAttributeTypeInstance) {
+            flash.message = "ExtendedAttributeType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ extendedAttributeTypeInstance : extendedAttributeTypeInstance ] }
+    }
+
+    def delete = {
+        def extendedAttributeTypeInstance = ExtendedAttributeType.get( params.id )
+        if(extendedAttributeTypeInstance) {
+            try {
+                extendedAttributeTypeInstance.delete(flush:true)
+                flash.message = "ExtendedAttributeType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "ExtendedAttributeType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "ExtendedAttributeType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def extendedAttributeTypeInstance = ExtendedAttributeType.get( params.id )
+
+        if(!extendedAttributeTypeInstance) {
+            flash.message = "ExtendedAttributeType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ extendedAttributeTypeInstance : extendedAttributeTypeInstance ]
+        }
+    }
+
+    def update = {
+        def extendedAttributeTypeInstance = ExtendedAttributeType.get( params.id )
+        if(extendedAttributeTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(extendedAttributeTypeInstance.version > version) {
+                    
+                    extendedAttributeTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[extendedAttributeTypeInstance:extendedAttributeTypeInstance])
+                    return
+                }
+            }
+            extendedAttributeTypeInstance.properties = params
+            if(!extendedAttributeTypeInstance.hasErrors() && extendedAttributeTypeInstance.save(flush: true)) {
+                flash.message = "ExtendedAttributeType ${params.id} updated"
+                redirect(action:show,id:extendedAttributeTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[extendedAttributeTypeInstance:extendedAttributeTypeInstance])
+            }
+        }
+        else {
+            flash.message = "ExtendedAttributeType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def extendedAttributeTypeInstance = new ExtendedAttributeType()
+        extendedAttributeTypeInstance.properties = params
+        return ['extendedAttributeTypeInstance':extendedAttributeTypeInstance]
+    }
+
+    def save = {
+        def extendedAttributeTypeInstance = new ExtendedAttributeType(params)
+        if(!extendedAttributeTypeInstance.hasErrors() && extendedAttributeTypeInstance.save(flush: true)) {
+            flash.message = "ExtendedAttributeType ${extendedAttributeTypeInstance.id} created"
+            redirect(action:show,id:extendedAttributeTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[extendedAttributeTypeInstance:extendedAttributeTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryGroupDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryGroupDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryGroupDetailedController.groovy	(revision 875)
@@ -0,0 +1,113 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class InventoryGroupDetailedController extends BaseController {
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ inventoryGroupInstanceList: InventoryGroup.list( params ), inventoryGroupInstanceTotal: InventoryGroup.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def inventoryGroupInstance = InventoryGroup.get( params.id )
+
+        if(!inventoryGroupInstance) {
+            flash.message = "InventoryGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ inventoryGroupInstance : inventoryGroupInstance ] }
+    }
+
+    def delete = {
+        def inventoryGroupInstance = InventoryGroup.get( params.id )
+        if(inventoryGroupInstance) {
+            try {
+                inventoryGroupInstance.delete(flush:true)
+                flash.message = "InventoryGroup ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "InventoryGroup ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "InventoryGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def inventoryGroupInstance = InventoryGroup.get( params.id )
+
+        if(!inventoryGroupInstance) {
+            flash.message = "InventoryGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ inventoryGroupInstance : inventoryGroupInstance ]
+        }
+    }
+
+    def update = {
+        def inventoryGroupInstance = InventoryGroup.get( params.id )
+        if(inventoryGroupInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(inventoryGroupInstance.version > version) {
+                    
+                    inventoryGroupInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[inventoryGroupInstance:inventoryGroupInstance])
+                    return
+                }
+            }
+            inventoryGroupInstance.properties = params
+            if(!inventoryGroupInstance.hasErrors() && inventoryGroupInstance.save(flush: true)) {
+                flash.message = "InventoryGroup ${params.id} updated"
+                redirect(action:show,id:inventoryGroupInstance.id)
+            }
+            else {
+                render(view:'edit',model:[inventoryGroupInstance:inventoryGroupInstance])
+            }
+        }
+        else {
+            flash.message = "InventoryGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def inventoryGroupInstance = new InventoryGroup()
+        inventoryGroupInstance.properties = params
+        return ['inventoryGroupInstance':inventoryGroupInstance]
+    }
+
+    def save = {
+        def inventoryGroupInstance = new InventoryGroup(params)
+        if(!inventoryGroupInstance.hasErrors() && inventoryGroupInstance.save(flush: true)) {
+            flash.message = "InventoryGroup ${inventoryGroupInstance.id} created"
+            redirect(action:show,id:inventoryGroupInstance.id)
+        }
+        else {
+            render(view:'create',model:[inventoryGroupInstance:inventoryGroupInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryItemDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryItemDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryItemDetailedController.groovy	(revision 875)
@@ -0,0 +1,703 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import com.zeddware.grails.plugins.filterpane.FilterUtils
+import org.springframework.web.servlet.support.RequestContextUtils as RCU
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+class InventoryItemDetailedController extends BaseController {
+
+    def filterService
+    def exportService
+    def inventoryCsvService
+    def inventoryItemService
+    def inventoryItemSearchService
+    def inventoryMovementService
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST', useInventoryItem:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def index = { redirect(action:search, params:params) }
+
+    /**
+    * Set session.inventoryItemSearchParamsMax
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def setSearchParamsMax = {
+        def max = 1000
+        if(params.newMax?.isInteger()) {
+            def i = params.newMax.toInteger()
+            if(i > 0 && i <= max)
+                session.inventoryItemSearchParamsMax = params.newMax
+            if(i > max)
+                session.inventoryItemSearchParamsMax = max
+        }
+        forward(action: 'search', params: params)
+    }
+
+    /**
+    * Set session.inventoryItemReorderSearchParamsMax
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def setReorderSearchParamsMax = {
+        def max = 1000
+        if(params.newMax?.isInteger()) {
+            def i = params.newMax.toInteger()
+            if(i > 0 && i <= max)
+                session.inventoryItemReorderSearchParamsMax = params.newMax
+            if(i > max)
+                session.inventoryItemReorderSearchParamsMax = max
+        }
+        forward(action: 'reorder', params: params)
+    }
+
+    /**
+    * Display the import view.
+    */
+    def importInventoryItemPictures = {
+    }
+
+    /**
+    * Handle the import save.
+    */
+    def importInventoryItemPicturesSave = {
+        def result = inventoryItemService.importInventoryItemPictures(request)
+
+        if(!result.error) {
+            def logFileLink = g.link(controller: "appCore", action: "appLog") {"log"}
+            flash.message = g.message(code: "inventoryItemPictures.import.success", args: [logFileLink])
+            redirect(action:search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: importInventoryItemPictures)
+    }
+
+    /**
+    * Display the import view.
+    */
+    def importInventory = {
+    }
+
+    /**
+    * Handle the import save.
+    */
+    def importInventorySave = {
+        def result = inventoryCsvService.importInventory(request)
+
+        if(!result.error) {
+            flash.message = g.message(code: "inventory.import.success")
+            redirect(action:search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: importInventory)
+    }
+
+    /**
+    * Export a csv template.
+    * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time!
+    * This does not appear to be a problem once deployed to Tomcat.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def exportInventoryTemplate = {
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=InventoryTemplate.csv")
+        def s = inventoryCsvService.buildInventoryTemplate()
+        render s
+    }
+
+    /**
+    * Export a csv test file.
+    */
+    def exportInventoryExample = {
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=InventoryExample.csv")
+        def s = inventoryCsvService.buildInventoryExample()
+        render s
+    }
+
+    /**
+    * Export the entire inventory as a csv file.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def exportInventory = {
+
+        def inventoryItemList = InventoryItem.list()
+
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=Inventory.csv")
+        def s = inventoryCsvService.buildInventory(inventoryItemList)
+        render s
+    }
+
+    /**
+    * Display the import view for purchases.
+    */
+    def importInventoryItemPurchases = {
+    }
+
+    /**
+    * Handle the inventory purchases import save.
+    */
+    def importInventoryItemPurchasesSave = {
+        def result = inventoryCsvService.importInventoryItemPurchases(request)
+
+        if(!result.error) {
+            flash.message = g.message(code: "inventory.import.success")
+            redirect(action:search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: importInventoryItemPurchases)
+    }
+
+    /**
+    * Search for Inventory items.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def search = {
+
+        if(session.inventoryItemSearchParamsMax)
+            params.max = session.inventoryItemSearchParamsMax
+
+        // Protect filterPane.
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  1000)
+
+        def inventoryItemInstanceList = []
+        def inventoryItemInstanceTotal
+        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+        def isFilterApplied = FilterUtils.isFilterApplied(params)
+
+        // Restore default sort if a new text search is requested
+        if(params.newTextSearch) {
+            params.sort = 'id'
+            params.order = 'desc'
+        }
+
+        // Restore search unless a new search is being requested.
+        if(!params.searchText && !params.quickSearch && !filterParams) {
+            if(session.inventoryItemSearchText) {
+                params.searchText = session.inventoryItemSearchText
+                params.searchName = session.inventoryItemSearchName
+                params.searchDescription = session.inventoryItemSearchDescription
+                params.searchComment = session.inventoryItemSearchComment
+                params.searchLocation = session.inventoryItemSearchLocation
+                params.searchGroup = session.inventoryItemSearchGroup
+                params.searchSpareFor = session.inventoryItemSearchSpareFor
+            }
+            else if(session.inventoryItemQuickSearch) {
+                params.quickSearch = session.inventoryItemQuickSearch
+                if(session.inventoryItemQuickSearchDaysBack)
+                    params.daysBack = session.inventoryItemQuickSearchDaysBack.toString()
+            }
+            else if(session.inventoryItemSearchFilterParams) {
+                session.inventoryItemSearchFilterParams.each() { params[it.key] = it.value }
+                params.filter = session.inventoryItemSearchFilter
+                isFilterApplied = FilterUtils.isFilterApplied(params)
+            }
+        }
+
+        // Remember sort if supplied, otherwise try to restore.
+        if(params.sort && params.order) {
+             session.inventoryItemSearchSort = params.sort
+             session.inventoryItemSearchOrder = params.order
+        }
+        else if(session.inventoryItemSearchSort && session.inventoryItemSearchOrder) {
+            params.sort = session.inventoryItemSearchSort
+            params.order = session.inventoryItemSearchOrder
+        }
+
+        if(isFilterApplied) {
+            // filterPane:
+            inventoryItemInstanceList = filterService.filter( params, InventoryItem )
+            inventoryItemInstanceTotal = filterService.count( params, InventoryItem )
+            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+            // Remember search.
+            session.inventoryItemSearchFilterParams = new LinkedHashMap(filterParams)
+            session.inventoryItemSearchFilter = new LinkedHashMap(params.filter)
+            // Clear any previous search.
+            session.removeAttribute("inventoryItemSearchText")
+            session.removeAttribute("inventoryItemSearchName")
+            session.removeAttribute("inventoryItemSearchDescription")
+            session.removeAttribute("inventoryItemSearchComment")
+            session.removeAttribute("inventoryItemSearchLocation")
+            session.removeAttribute("inventoryItemSearchGroup")
+            session.removeAttribute("inventoryItemSearchSpareFor")
+            session.removeAttribute("inventoryItemQuickSearch")
+            session.removeAttribute("inventoryItemQuickSearchDaysBack")
+        }
+        else if(params.searchText) {
+            // Text Search:
+            def result = inventoryItemSearchService.getTextSearch(params, RCU.getLocale(request))
+            inventoryItemInstanceList = result.inventoryItemList
+            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
+            params.message = result.message
+            filterParams.searchText = result.searchText
+            // Place limit search selects in filterParams for pagination.
+            if(params.searchName)
+                filterParams.searchName = params.searchName
+            if(params.searchDescription)
+                filterParams.searchDescription = params.searchDescription
+            if(params.searchComment)
+                filterParams.searchComment = params.searchComment
+            if(params.searchLocation)
+                filterParams.searchLocation = params.searchLocation
+            if(params.searchGroup)
+                filterParams.searchGroup = params.searchGroup
+            if(params.searchSpareFor)
+                filterParams.searchSpareFor = params.searchSpareFor
+            // Remember search.
+            session.inventoryItemSearchText = params.searchText
+            session.inventoryItemSearchName = params.searchName
+            session.inventoryItemSearchDescription = params.searchDescription
+            session.inventoryItemSearchComment = params.searchComment
+            session.inventoryItemSearchLocation = params.searchLocation
+            session.inventoryItemSearchGroup = params.searchGroup
+            session.inventoryItemSearchSpareFor = params.searchSpareFor
+            // Clear any previous search.
+            session.removeAttribute("inventoryItemQuickSearch")
+            session.removeAttribute("inventoryItemQuickSearchDaysBack")
+            session.removeAttribute("inventoryItemSearchFilterParams")
+            session.removeAttribute("inventoryItemSearchFilter")
+        }
+        else {
+            // Quick Search Links:
+            if(!params.quickSearch) params.quickSearch = "all"
+            def result = inventoryItemSearchService.getQuickSearch(params, RCU.getLocale(request))
+            inventoryItemInstanceList = result.inventoryItemList
+            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
+            params.message = result.message
+            filterParams.quickSearch = result.quickSearch
+            // Remember search.
+            session.inventoryItemQuickSearch = result.quickSearch
+            if(result.daysBack)
+                session.inventoryItemQuickSearchDaysBack = result.daysBack
+            // Clear any previous search.
+            session.removeAttribute("inventoryItemSearchText")
+            session.removeAttribute("inventoryItemSearchName")
+            session.removeAttribute("inventoryItemSearchDescription")
+            session.removeAttribute("inventoryItemSearchComment")
+            session.removeAttribute("inventoryItemSearchLocation")
+            session.removeAttribute("inventoryItemSearchGroup")
+            session.removeAttribute("inventoryItemSearchSpareFor")
+            session.removeAttribute("inventoryItemSearchFilterParams")
+            session.removeAttribute("inventoryItemSearchFilter")
+        }
+
+        // export plugin:
+        if(params?.format && params.format != "html") {
+
+            def dateFmt = { date ->
+                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
+            }
+
+            String title
+            if(params.quickSearch)
+                title = params.message
+            else
+                title = "Filtered Inventory List."
+
+            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
+            response.setHeader("Content-disposition", "attachment; filename=Inventory.${params.extension}")
+            List fields = ["name",
+                                "description",
+                                "inventoryGroup",
+                                "unitsInStock",
+                                "reorderPoint",
+                                "unitOfMeasure",
+                                "inventoryLocation",
+                                "inventoryLocation.inventoryStore"]
+            Map labels = ["name": "Name",
+                                "description": "Description",
+                                "inventoryGroup": "Group",
+                                "unitsInStock":"In Stock",
+                                "reorderPoint":"Reorder Point",
+                                "unitOfMeasure": "UOM",
+                                "inventoryLocation": "Location",
+                                "inventoryLocation.inventoryStore": "Store"]
+
+            Map formatters = [:]
+            Map parameters = [title: title, separator: ","]
+
+            exportService.export(params.format,
+                                                response.outputStream,
+                                                inventoryItemInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) },
+                                                fields,
+                                                labels,
+                                                formatters,
+                                                parameters)
+        }
+
+        // Add some basic params to filterParams.
+        filterParams.max = params.max
+        filterParams.offset = params.offset?.toInteger() ?: 0
+        filterParams.sort = params.sort ?: "name"
+        filterParams.order = params.order ?: "asc"
+
+        // Get some associatedProperty values for filterpane.
+        def associatedPropertyValues = [:]
+        def associatedPropertyMax = 10000
+        associatedPropertyValues.inventoryLocationList = InventoryLocation.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
+        associatedPropertyValues.assetList = Asset.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
+        associatedPropertyValues.supplierList = Supplier.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
+
+        return[ inventoryItemInstanceList: inventoryItemInstanceList,
+                        inventoryItemInstanceTotal: inventoryItemInstanceTotal,
+                        filterParams: filterParams,
+                        params: params,
+                        associatedPropertyValues: associatedPropertyValues ]
+    } // end search()
+
+    /**
+    * Simply assigns a passed in task id to a session variable and redirects to search.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def findInventoryItemForMovement = {
+        if(!params.task?.id) {
+            flash.message = "No task id supplied, please select a task then the inventory tab."
+            redirect(controller: "taskDetailed", action: "search")
+            return
+        }
+
+        session.inventoryMovementTaskId = params.task.id
+        flash.message = "Please find and then select the inventory item."
+        redirect(action: search)
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def result = inventoryItemService.show(params)
+
+        if(!result.error) {
+
+            def model = [ inventoryItemInstance: result.inventoryItemInstance,
+                                    inventoryMovementList: result.inventoryMovementList,
+                                    inventoryMovementListTotal: result.inventoryMovementListTotal,
+                                    inventoryMovementListMax: result.inventoryMovementListMax,
+                                    inventoryItemPurchases: result.inventoryItemPurchases,
+                                    inventoryItemPurchasesTotal: result.inventoryItemPurchasesTotal,
+                                    showTab: result.showTab]
+
+            if(session.inventoryMovementTaskId) {
+                model.inventoryMovementInstance = new InventoryMovement()
+                model.inventoryMovementInstance.task = Task.get(session.inventoryMovementTaskId)
+                model.inventoryMovementInstance.quantity = 1
+            }
+
+            // Success.
+            return model
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action:search)
+    }
+
+    def delete = {
+        def result = inventoryItemService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["InventoryItem", params.id])
+            redirect(action:search)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(action:search)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def result = inventoryItemService.edit(params)
+
+        if(!result.error) {
+            def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+            return [ inventoryItemInstance : result.inventoryItemInstance,
+                            suppliers: suppliers]
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action:search)
+    }
+
+    def update = {
+        def result = inventoryItemService.update(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.update.success", args: ["InventoryItem", params.id])
+            redirect(action:show, id: params.id)
+            return
+        }
+
+        if(result.error.code == "default.not.found") {
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+            redirect(action:search)
+            return
+        }
+
+        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+        render(view:'edit', model:[inventoryItemInstance: result.inventoryItemInstance,
+                                                suppliers: suppliers])
+    }
+
+    def create = {
+        def result = inventoryItemService.create(params)
+        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+        if(!result.error)
+            return [inventoryItemInstance: result.inventoryItemInstance,
+                            suppliers: suppliers]
+
+        //flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: search)
+    }
+
+    def save = {
+        def result = inventoryItemService.save(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["InventoryItem", result.inventoryItemInstance.id])
+            redirect(action:show, id: result.inventoryItemInstance.id)
+            return
+        }
+
+        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+        //flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        render(view:'create', model:[inventoryItemInstance: result.inventoryItemInstance,
+                                                    suppliers: suppliers])
+    }
+
+    /**
+    * Handles the use inventory item form submit in the show view.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def useInventoryItem = {
+
+        params.inventoryMovementType = InventoryMovementType.get(1) // Set type to "Used".
+        def result = inventoryMovementService.move(params)
+
+        if(!result.error) {
+            flash.message = "Inventory Movement for ${result.inventoryMovementInstance.inventoryItem.name.encodeAsHTML()} created."
+            session.inventoryMovementTaskId = null
+            redirect(controller: "taskDetailed",
+                            action: "show",
+                            id: result.taskId,
+                            params: [showTab: "showInventoryTab"])
+            // Success.
+            return
+        }
+
+        // Prepare data for the show view.
+        def p = [:]
+        p.id = result.inventoryMovementInstance.inventoryItem?.id
+        def r = inventoryItemService.show(p)
+
+        // Render show view if data was successfully prepared.
+        if(!r.error) {
+            def model = [ inventoryItemInstance: r.inventoryItemInstance,
+                                    inventoryMovementList: r.inventoryMovementList,
+                                    inventoryMovementListTotal: r.inventoryMovementListTotal,
+                                    inventoryMovementListMax: r.inventoryMovementListMax,
+                                    inventoryItemPurchases: r.inventoryItemPurchases,
+                                    inventoryItemPurchasesTotal: r.inventoryItemPurchasesTotal,
+                                    showTab: r.showTab]
+
+            model.inventoryMovementInstance = result.inventoryMovementInstance // This will pass in the errors.
+
+            render(view: 'show', model: model)
+            return
+        }
+
+        // Could not prepare data for show view so doing the next best thing.
+        flash.errorMessage = g.message(code: r.error.code, args: r.error.args)
+        redirect(action:search)
+
+    } // useInventoryItem
+
+    /**
+    * Clear the use inventory item form in the show view.
+    * Accomplished by clearing the session variable and ajax.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def clearUseInventoryItem = {
+            session.inventoryMovementTaskId = null
+            render ''
+    }
+
+    /**
+    * Search for Inventory items that require reorder.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+    def reorder = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_reorder)
+            params.action='reorder'
+
+        if(session.inventoryItemReorderSearchParamsMax)
+            params.max = session.inventoryItemReorderSearchParamsMax
+
+        def inventoryItemInstanceList = []
+        def inventoryItemInstanceTotal
+        def filterParams = params
+        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+        def inventoryGroups = InventoryGroup.findAllByIsActive(true)
+
+        if(params.selectedGroups) {
+            if(params.selectedGroups instanceof String)
+                params.selectedGroups = [params.selectedGroups.toLong()]
+            else
+                params.selectedGroups = params.selectedGroups.collect { it.toLong() }
+        }
+        else
+                params.selectedGroups = []
+
+        // Restore search unless a new search is being requested.
+        if(!params.newSearch && !params.quickSearch) {
+            if(session.reorderSearchSelectedGroups) {
+                params.selectedGroups = session.reorderSearchSelectedGroups
+                params.selectedSupplier = session.reorderSearchSelectedSupplier
+                params.includeAlternateSuppliers = session.reorderSearchIncludeAlternateSuppliers
+                params.includeReorderListingDisabled = session.reorderSearchIncludeReorderListingDisabled
+                params.includeOnBackOrder = session.reorderSearchIncludeOnBackOrder
+            }
+            else if(session.inventoryItemReorderQuickSearch) {
+                params.quickSearch = session.inventoryItemReorderQuickSearch
+                if(session.inventoryItemReorderQuickSearchDaysBack)
+                    params.daysBack = session.inventoryItemReorderQuickSearchDaysBack.toString()
+            }
+        }
+
+        // Remember sort if supplied, otherwise try to restore.
+        if(params.sort && params.order) {
+             session.inventoryItemReorderSearchSort = params.sort
+             session.inventoryItemReorderSearchOrder = params.order
+        }
+        else if(session.inventoryItemReorderSearchSort && session.inventoryItemReorderSearchOrder) {
+            params.sort = session.inventoryItemReorderSearchSort
+            params.order = session.inventoryItemReorderSearchOrder
+        }
+
+        if(params.quickSearch) {
+            // Quick Search Links:
+            if(!params.quickSearch) params.quickSearch = "inventoryBelowReorder"
+            def result = inventoryItemSearchService.getQuickSearch(params, RCU.getLocale(request))
+            inventoryItemInstanceList = result.inventoryItemList
+            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
+            params.message = result.message
+            filterParams.quickSearch = result.quickSearch
+            // Remember search.
+            session.inventoryItemReorderQuickSearch = result.quickSearch
+            if(result.daysBack)
+                session.inventoryItemReorderQuickSearchDaysBack = result.daysBack
+            // Clear any previous search.
+            session.removeAttribute("reorderSearchSelectedGroups")
+            session.removeAttribute("reorderSearchSelectedSupplier")
+            session.removeAttribute("reorderSearchIncludeAlternateSuppliers")
+            session.removeAttribute("reorderSearchIncludeReorderListingDisabled")
+            session.removeAttribute("reorderSearchIncludeOnBackOrder")
+        }
+        else {
+            // Reorder Search:
+            def result = inventoryItemSearchService.getReorderSearch(params, RCU.getLocale(request))
+            inventoryItemInstanceList = result.inventoryItemList
+            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
+            params.message = result.message
+            // Place limit search selects in filterParams for pagination.
+            if(params.selectedGroups) {
+                filterParams.selectedGroups = params.selectedGroups
+                filterParams.selectedSupplier = params.selectedSupplier
+                filterParams.includeAlternateSuppliers = params.includeAlternateSuppliers
+                filterParams.includeReorderListingDisabled = params.includeReorderListingDisabled
+                filterParams.includeOnBackOrder = params.includeOnBackOrder
+            }
+            // Remember search.
+            session.reorderSearchSelectedGroups = params.selectedGroups
+            session.reorderSearchSelectedSupplier = params.selectedSupplier
+            session.reorderSearchIncludeAlternateSuppliers = params.includeAlternateSuppliers
+            session.reorderSearchIncludeReorderListingDisabled = params.includeReorderListingDisabled
+            session.reorderSearchIncludeOnBackOrder = params.includeOnBackOrder
+            // Clear any previous search.
+            session.removeAttribute("inventoryItemReorderQuickSearch")
+            session.removeAttribute("inventoryItemReorderQuickSearchDaysBack")
+        }
+
+        // export plugin:
+        if(params?.format && params.format != "html") {
+
+            def dateFmt = { date ->
+                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
+            }
+
+            String title
+            if(params.quickSearch)
+                title = params.message
+            else
+                title = "Filtered Inventory List."
+
+            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
+            response.setHeader("Content-disposition", "attachment; filename=Inventory.${params.extension}")
+            List fields = ["name",
+                                "description",
+                                "inventoryGroup",
+                                "unitsInStock",
+                                "reorderPoint",
+                                "unitOfMeasure",
+                                "inventoryLocation",
+                                "inventoryLocation.inventoryStore"]
+            Map labels = ["name": "Name",
+                                "description": "Description",
+                                "inventoryGroup": "Group",
+                                "unitsInStock":"In Stock",
+                                "reorderPoint":"Reorder Point",
+                                "unitOfMeasure": "UOM",
+                                "inventoryLocation": "Location",
+                                "inventoryLocation.inventoryStore": "Store"]
+
+            Map formatters = [:]
+            Map parameters = [title: title, separator: ","]
+
+            exportService.export(params.format,
+                                                response.outputStream,
+                                                inventoryItemInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) },
+                                                fields,
+                                                labels,
+                                                formatters,
+                                                parameters)
+        }
+
+        // Add some basic params to filterParams.
+        filterParams.max = params.max
+        filterParams.offset = params.offset?.toInteger() ?: 0
+        filterParams.sort = params.sort ?: "name"
+        filterParams.order = params.order ?: "asc"
+
+        return[ inventoryItemInstanceList: inventoryItemInstanceList,
+                        inventoryItemInstanceTotal: inventoryItemInstanceTotal,
+                        filterParams: filterParams,
+                        params: params,
+                        inventoryGroups: inventoryGroups,
+                        suppliers: suppliers]
+    } // end reorder()
+
+} // end of class
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryItemPurchaseDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryItemPurchaseDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryItemPurchaseDetailedController.groovy	(revision 875)
@@ -0,0 +1,406 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import com.zeddware.grails.plugins.filterpane.FilterUtils
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+class InventoryItemPurchaseDetailedController extends BaseController {
+
+    def authService
+    def filterService
+    def exportService
+    def dateUtilService
+    def inventoryPurchaseService
+
+    def index = {
+        redirect(action:'search', params:params)
+    }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def setSearchParamsMax = {
+        def max = 1000
+        if(params.newMax?.isInteger()) {
+            def i = params.newMax.toInteger()
+            if(i > 0 && i <= max)
+                session.inventoryItemPurchaseSearchParamsMax = params.newMax
+            if(i > max)
+                session.inventoryItemPurchaseSearchParamsMax = max
+        }
+        forward(action: 'search', params: params)
+    }
+
+    def search = {
+
+        if(session.inventoryItemPurchaseSearchParamsMax)
+            params.max = session.inventoryItemPurchaseSearchParamsMax
+
+        // Protect filterPane.
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  1000 )
+        params.offset = params.offset?.toInteger() ?: 0
+
+        def inventoryItemPurchaseList = []
+        def inventoryItemPurchaseTotal
+        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+        def isFilterApplied = FilterUtils.isFilterApplied(params)
+
+        // Restore search unless a new search is being requested.
+        if(!params.quickSearch && !filterParams) {
+            if(session.inventoryItemPurchaseQuickSearch)
+                params.quickSearch = session.inventoryItemPurchaseQuickSearch
+            else if(session.inventoryItemPurchaseSearchFilterParams) {
+                session.inventoryItemPurchaseSearchFilterParams.each() { params[it.key] = it.value }
+                params.filter = session.inventoryItemPurchaseSearchFilter
+                isFilterApplied = FilterUtils.isFilterApplied(params)
+            }
+        }
+
+        // Remember sort if supplied, otherwise try to restore.
+        if(params.sort && params.order) {
+            // Reset to defaultSort if requested.
+            if(params.sort == 'defaultSort') {
+                params.sort = null
+                params.order = null
+                session.removeAttribute("inventoryItemPurchaseSearchSort")
+                session.removeAttribute("inventoryItemPurchaseSearchOrder")
+            }
+            else {
+                session.inventoryItemPurchaseSearchSort = params.sort
+                session.inventoryItemPurchaseSearchOrder = params.order
+            }
+        }
+        else if(session.inventoryItemPurchaseSearchSort && session.inventoryItemPurchaseSearchOrder) {
+            params.sort = session.inventoryItemPurchaseSearchSort
+            params.order = session.inventoryItemPurchaseSearchOrder
+        }
+        else {
+            params.sort = "id"
+            params.order = "asc"
+        }
+
+        if(isFilterApplied) {
+            // filterPane:
+            //if(params.sort == "attentionFlag") // See ticket #64 in Trac.
+                //params.sort = "id"
+
+            // Call filterService.
+            inventoryItemPurchaseList = filterService.filter( params, InventoryItemPurchase )
+            inventoryItemPurchaseTotal = filterService.count( params, InventoryItemPurchase )
+            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+            // Remember search.
+            session.inventoryItemPurchaseSearchFilterParams = new LinkedHashMap(filterParams)
+            session.inventoryItemPurchaseSearchFilter = new LinkedHashMap(params.filter)
+            session.removeAttribute("inventoryItemPurchaseQuickSearch")
+        }
+        else {
+            // Quick Search:
+
+            if(params.quickSearch == "searchAllOrders") {
+                def orderType = InventoryItemPurchaseType.read(1)
+                inventoryItemPurchaseList = InventoryItemPurchase.findAllByInventoryItemPurchaseType(orderType,
+                                                                                                                                                                [max:params.max,
+                                                                                                                                                                offset:params.offset,
+                                                                                                                                                                sort:params.sort,
+                                                                                                                                                                order:params.order])
+                inventoryItemPurchaseTotal = InventoryItemPurchase.countByInventoryItemPurchaseType(orderType)
+                if(inventoryItemPurchaseTotal > 0) { params.message = "All Orders." }
+                else { params.message = "No orders found." }
+            }
+            else if(params.quickSearch == "searchAllReceived") {
+                def receivedBackOrderType = InventoryItemPurchaseType.read(2)
+                def receivedCompleteType = InventoryItemPurchaseType.read(3)
+                inventoryItemPurchaseList = InventoryItemPurchase.findAllByInventoryItemPurchaseTypeOrInventoryItemPurchaseType(receivedBackOrderType,
+                                                                                                                                                                                                                receivedCompleteType,
+                                                                                                                                                                                                                [max:params.max,
+                                                                                                                                                                                                                offset:params.offset,
+                                                                                                                                                                                                                sort:params.sort,
+                                                                                                                                                                                                                order:params.order])
+                inventoryItemPurchaseTotal = InventoryItemPurchase.countByInventoryItemPurchaseTypeOrInventoryItemPurchaseType(receivedBackOrderType,
+                                                                                                                                                                                                                receivedCompleteType)
+                if(inventoryItemPurchaseTotal > 0) { params.message = "All Received." }
+                else { params.message = "No orders found." }
+            }
+            else {
+                //Default:
+                inventoryItemPurchaseList = InventoryItemPurchase.list(max:params.max,
+                                                                                                            offset:params.offset,
+                                                                                                            sort:params.sort,
+                                                                                                            order:params.order)
+                inventoryItemPurchaseTotal = InventoryItemPurchase.count()
+                if(inventoryItemPurchaseTotal > 0) { params.message = "All Purchases." }
+                else { params.message = "No orders found." }
+            }
+
+            filterParams.quickSearch = params.quickSearch
+            // Remember search.
+            session.removeAttribute("inventoryItemPurchaseSearchFilterParams")
+            session.removeAttribute("inventoryItemPurchaseSearchFilter")
+            session.inventoryItemPurchaseQuickSearch = params.quickSearch
+        }
+
+        // export plugin:
+        if(params?.format && params.format != "html") {
+
+            def dateFmt = { date ->
+                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
+            }
+
+            String title
+            if(params.quickSearch)
+                title = "${params.quickSearch} inventory purchases."
+            else
+                title = "Filtered inventory purchases."
+
+            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
+            response.setHeader("Content-disposition", "attachment; filename=Purchases.${params.extension}")
+            List fields = ["purchaseOrderNumber", "date", "costCode", "quantity", "orderValueAmount", "invoiceNumber",
+                                    "inventoryItemPurchaseType"]
+            Map labels = ["purchaseOrderNumber": "Order Number", "date": "Date", "costCode": "Cost Code",
+                                    "quantity": "Quantity", "orderValueAmount": "Order \$", "invoiceNumber": "Invoice Number",
+                                    "inventoryItemPurchaseType": "Type"]
+            Map formatters = [ date: dateFmt]
+            Map parameters = [title: title, separator: ","]
+
+            exportService.export(params.format, response.outputStream, inventoryItemPurchaseList, fields, labels, formatters, parameters)
+        }
+
+        // Add some basic params to filterParams.
+        filterParams.max = params.max
+        filterParams.offset = params.offset?.toInteger() ?: 0
+        filterParams.sort = params.sort ?: "purchaseOrderNumber"
+        filterParams.order = params.order ?: "desc"
+
+        // Get some associatedProperty values for filterpane.
+        def associatedPropertyValues = [:]
+        def startOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), -10))
+        def endOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), 10))
+        associatedPropertyValues.yearRange = startOfYearRange..endOfYearRange
+
+        return[ inventoryItemPurchaseList: inventoryItemPurchaseList,
+                        inventoryItemPurchaseTotal: inventoryItemPurchaseTotal,
+                        filterParams: filterParams,
+                        associatedPropertyValues: associatedPropertyValues ]
+
+    } // end search()
+
+    def show = {
+        def inventoryItemPurchaseInstance = InventoryItemPurchase.read( params.id )
+        params.returnTo = params.returnTo ?: 'inventoryItem'
+
+        if(!inventoryItemPurchaseInstance) {
+            flash.message = "InventoryItemPurchase not found with id ${params.id}"
+            redirect(controller: 'inventoryItemDetailed', action:'search')
+        }
+        else { return [ inventoryItemPurchaseInstance : inventoryItemPurchaseInstance ] }
+    }
+
+    def delete = {
+        def result = inventoryPurchaseService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["InventoryItemPurchase", params.id])
+            if(params.returnTo == 'inventoryItem') {
+                redirect(controller: 'inventoryItemDetailed',
+                                action: 'show',
+                                id: result.inventoryItemId,
+                                params: [showTab: "showPurchasingTab"])
+            }
+            else {
+                redirect(action: 'search')
+            }
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(controller: 'inventoryItemDetailed', action: 'search')
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+        def result = inventoryPurchaseService.edit(params)
+        params.returnTo = params.returnTo ?: 'inventoryItem'
+
+        def costCodes = []
+
+        if(!result.error) {
+            if(inventoryPurchaseService.isPersonInPurchasingGroup(result.inventoryItemPurchaseInstance.costCode.purchasingGroup))
+                costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
+            return [ inventoryItemPurchaseInstance : result.inventoryItemPurchaseInstance,
+                            'costCodes': costCodes ]
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(controller: 'inventoryItemDetailed', action:'search', params:params)
+    }
+
+    def update = {
+        def result = inventoryPurchaseService.update(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.update.success", args: ["Inventory Purchase", params.id])
+            redirect(action:show, id: params.id)
+            return
+        }
+
+        if(result.error.code == "default.not.found") {
+            flash.message = g.message(code: result.error.code, args: result.error.args)
+            redirect(controller: 'inventoryItemDetailed', action:'search', params:params)
+            return
+        }
+
+        result.inventoryItemPurchaseInstance.attach()
+        result.inventoryItemPurchaseInstance.costCode.attach()
+        result.inventoryItemPurchaseInstance.costCode.purchasingGroup.attach()
+
+        def costCodes = []
+        if(inventoryPurchaseService.isPersonInPurchasingGroup(result.inventoryItemPurchaseInstance.costCode.purchasingGroup))
+            costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
+        render(view:'edit', model:[inventoryItemPurchaseInstance: result.inventoryItemPurchaseInstance,
+                                                'costCodes': costCodes])
+    }
+
+    def create = {
+        def inventoryItemPurchaseInstance = new InventoryItemPurchase()
+        inventoryItemPurchaseInstance.properties = params
+        params.returnTo = params.returnTo ?: 'inventoryItem'
+
+        if(!inventoryItemPurchaseInstance.inventoryItem) {
+            flash.message = "Please select an inventory item then the 'purchasing' tab."
+            redirect(controller: 'inventoryItemDetailed', action: 'search')
+            return
+        }
+
+        def costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
+        return ['inventoryItemPurchaseInstance': inventoryItemPurchaseInstance,
+                        'costCodes': costCodes]
+    }
+
+    def save = {
+        def result = inventoryPurchaseService.save(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["Inventory Purchase", ''])
+            if(params.returnTo == 'inventoryItem') {
+                redirect(controller: 'inventoryItemDetailed',
+                                action: 'show',
+                                id: result.inventoryItemId,
+                                params: [showTab: "showPurchasingTab"])
+            }
+            else {
+                redirect(action: 'search')
+            }
+            return
+        }
+
+        def costCodes = inventoryPurchaseService.getCostCodesByPerson()
+
+        params.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        render(view:'create', model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance,
+                                                    'costCodes': costCodes])
+    }
+
+    def receive = {
+        def inventoryItemPurchaseInstance = InventoryItemPurchase.read( params.id )
+
+        if(!inventoryItemPurchaseInstance) {
+            flash.message = "InventoryItemPurchase not found with id ${params.id}"
+            redirect(controller: 'inventoryItemDetailed', action:'search')
+            return
+        }
+
+        inventoryItemPurchaseInstance.properties = params
+        params.returnTo = params.returnTo ?: 'inventoryItem'
+        def calcQuantities = inventoryPurchaseService.calcQuantities(inventoryItemPurchaseInstance)
+        inventoryItemPurchaseInstance.quantity = calcQuantities.thisOrderRemaining
+        inventoryItemPurchaseInstance.orderValueAmount = calcQuantities.thisOrderRemainingAmount
+        return ['inventoryItemPurchaseInstance':inventoryItemPurchaseInstance,
+                        'orderId': inventoryItemPurchaseInstance.id]
+    }
+
+    def receiveSave = {
+        def result = inventoryPurchaseService.receiveSave(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["Inventory Purchase", ''])
+            if(params.returnTo == 'inventoryItem') {
+                redirect(controller: 'inventoryItemDetailed',
+                                action: 'show',
+                                id: result.inventoryItemId,
+                                params: [showTab: "showPurchasingTab"])
+            }
+            else {
+                redirect(action: 'search')
+            }
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(controller: 'inventoryItemDetailed', action: 'search')
+            return
+        }
+
+        // Prevent lazy initialization error.
+        result.inventoryItemPurchaseInstance.costCode.attach()
+
+        render(view:'receive',
+                        model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance,
+                                    'orderId': result.orderId])
+    }
+
+    def approveInvoicePayment = {
+        // Read the values from Order Received.
+        def inventoryItemPurchaseInstance = InventoryItemPurchase.read( params.id )
+
+        if(!inventoryItemPurchaseInstance) {
+            flash.message = "InventoryItemPurchase not found with id ${params.id}"
+            redirect(controller: 'inventoryItemDetailed', action:'search')
+            return
+        }
+
+        inventoryItemPurchaseInstance.properties = params
+        params.returnTo = params.returnTo ?: 'inventoryItem'
+        return ['inventoryItemPurchaseInstance':inventoryItemPurchaseInstance,
+                        'receivedId': inventoryItemPurchaseInstance.id]
+    }
+
+    def approveInvoicePaymentSave = {
+        def result = inventoryPurchaseService.approveInvoicePaymentSave(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["Inventory Purchase", ''])
+            if(params.returnTo == 'inventoryItem') {
+                redirect(controller: 'inventoryItemDetailed',
+                                action: 'show',
+                                id: result.inventoryItemId,
+                                params: [showTab: "showPurchasingTab"])
+            }
+            else {
+                redirect(action: 'search')
+            }
+            return
+        }
+
+        if(result.error.code == "default.not.found") {
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+            redirect(controller: 'inventoryItemDetailed', action: 'search')
+            return
+        }
+
+        // Prevent lazy initialization error.
+        result.inventoryItemPurchaseInstance.costCode.attach()
+
+        render(view:'approveInvoicePayment',
+                    model:['inventoryItemPurchaseInstance': result.inventoryItemPurchaseInstance,
+                                    'receivedId': result.receivedId])
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryLocationDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryLocationDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryLocationDetailedController.groovy	(revision 875)
@@ -0,0 +1,113 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+class InventoryLocationDetailedController extends BaseController {
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def index = { redirect(action:list,params:params) }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ inventoryLocationInstanceList: InventoryLocation.list( params ), inventoryLocationInstanceTotal: InventoryLocation.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def inventoryLocationInstance = InventoryLocation.get( params.id )
+
+        if(!inventoryLocationInstance) {
+            flash.message = "InventoryLocation not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ inventoryLocationInstance : inventoryLocationInstance ] }
+    }
+
+    def delete = {
+        def inventoryLocationInstance = InventoryLocation.get( params.id )
+        if(inventoryLocationInstance) {
+            try {
+                inventoryLocationInstance.delete(flush:true)
+                flash.message = "InventoryLocation ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "InventoryLocation ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "InventoryLocation not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def inventoryLocationInstance = InventoryLocation.get( params.id )
+
+        if(!inventoryLocationInstance) {
+            flash.message = "InventoryLocation not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ inventoryLocationInstance : inventoryLocationInstance ]
+        }
+    }
+
+    def update = {
+        def inventoryLocationInstance = InventoryLocation.get( params.id )
+        if(inventoryLocationInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(inventoryLocationInstance.version > version) {
+                    
+                    inventoryLocationInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[inventoryLocationInstance:inventoryLocationInstance])
+                    return
+                }
+            }
+            inventoryLocationInstance.properties = params
+            if(!inventoryLocationInstance.hasErrors() && inventoryLocationInstance.save(flush: true)) {
+                flash.message = "InventoryLocation ${params.id} updated"
+                redirect(action:show,id:inventoryLocationInstance.id)
+            }
+            else {
+                render(view:'edit',model:[inventoryLocationInstance:inventoryLocationInstance])
+            }
+        }
+        else {
+            flash.message = "InventoryLocation not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def inventoryLocationInstance = new InventoryLocation()
+        inventoryLocationInstance.properties = params
+        return ['inventoryLocationInstance':inventoryLocationInstance]
+    }
+
+    def save = {
+        def inventoryLocationInstance = new InventoryLocation(params)
+        if(!inventoryLocationInstance.hasErrors() && inventoryLocationInstance.save(flush: true)) {
+            flash.message = "InventoryLocation ${inventoryLocationInstance.id} created"
+            redirect(action:show,id:inventoryLocationInstance.id)
+        }
+        else {
+            render(view:'create',model:[inventoryLocationInstance:inventoryLocationInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryMovementDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryMovementDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryMovementDetailedController.groovy	(revision 875)
@@ -0,0 +1,116 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+class InventoryMovementDetailedController extends BaseController {
+
+    def inventoryMovementService
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST']
+
+    def index = { redirect(action:list,params:params) }
+
+    def list = {
+        flash.message = flash.message
+        redirect(controller:"taskDetailed", action:"search")
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def show = {
+        def inventoryMovementInstance = InventoryMovement.get( params.id )
+
+        if(!inventoryMovementInstance) {
+            flash.message = "InventoryMovement not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ inventoryMovementInstance : inventoryMovementInstance ] }
+    }
+
+    /**
+    * List the inventory movements for an InventoryItem.
+    * @param params.inventoryItem.id The id of an existing inventory item.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def listInventoryMovements = {
+        def inventoryItemInstance
+        if(params.id)
+            inventoryItemInstance = InventoryItem.get(params.id)
+        else if(params.inventoryItem?.id)
+            inventoryItemInstance = InventoryItem.get(params.inventoryItem.id)
+
+        if(!inventoryItemInstance) {
+            flash.message = "Inventory item not found with id ${params.id}"
+            redirect(controller:'inventoryItemDetailed', action: 'search')
+            return
+        }
+
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        def inventoryMovementList = InventoryMovement.findAllByInventoryItem(inventoryItemInstance, params)
+        def inventoryMovementListTotal = InventoryMovement.countByInventoryItem(inventoryItemInstance)
+
+        [ inventoryMovementList: inventoryMovementList,
+            inventoryMovementListTotal:  inventoryMovementListTotal,
+            inventoryItemInstance: inventoryItemInstance]
+    }
+
+    def delete = {
+        def result = inventoryMovementService.reverseMove(params)
+
+        if(!result.error) {
+            flash.message = "InventoryMovement ${params.id} deleted"
+            if(result.taskId) {
+                redirect(controller:"taskDetailed", action:"show", id:result.taskId)
+                return
+            }
+            redirect(controller:"inventoryItemDetailed", action:"show", id:result.inventoryItemInstance?.id)
+        }
+        else {
+            if(result.inventoryMovementInstance) {
+                render(view:'show',model:[inventoryMovementInstance:result.inventoryMovementInstance.attach()])
+            }
+            else {
+                flash.message = "Could not delete inventory movement."
+                redirect(controller:"taskDetailed", action:"search")
+            }
+        }
+    }
+
+    def create = {
+        def inventoryMovementInstance = new InventoryMovement()
+        inventoryMovementInstance.properties = params
+        def inventoryMovementTypeList = InventoryMovementType.withCriteria { gt("id", 1L) } // Don't include "Used".
+
+        return ['inventoryMovementInstance': inventoryMovementInstance,
+                        inventoryMovementTypeList: inventoryMovementTypeList]
+    }
+
+    /**
+    * Handles all inventory movements except those of type "Used".
+     * The "Used" type is handled directly by InventoryItemDetailedController and useInventoryItem.
+    */
+    def save = {
+        def result = inventoryMovementService.move(params)
+
+        if(!result.error) {
+            flash.message = "Inventory Movement for ${result.inventoryMovementInstance.inventoryItem.name} created."
+            if(result.taskId) {
+                redirect(controller:"taskDetailed", action:"show", id: result.taskId)
+                return
+            }
+            redirect(controller:"inventoryItemDetailed", action:"show", id: result.inventoryMovementInstance.inventoryItem.id)
+        }
+        else {
+            if(result.inventoryMovementInstance) {
+                def inventoryMovementTypeList = InventoryMovementType.withCriteria { gt("id", 1L) } // Don't include "Used".
+                render(view:'create', model:[inventoryMovementInstance: result.inventoryMovementInstance,
+                                                            inventoryMovementTypeList: inventoryMovementTypeList])
+            }
+            else {
+                flash.message = "Could not create inventory movement."
+                redirect(controller:"taskDetailed", action:"search", id:result.taskId)
+            }
+
+        }
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryMovementTypeController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryMovementTypeController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryMovementTypeController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class InventoryMovementTypeController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ inventoryMovementTypeInstanceList: InventoryMovementType.list( params ), inventoryMovementTypeInstanceTotal: InventoryMovementType.count() ]
+    }
+
+    def show = {
+        def inventoryMovementTypeInstance = InventoryMovementType.get( params.id )
+
+        if(!inventoryMovementTypeInstance) {
+            flash.message = "InventoryMovementType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ inventoryMovementTypeInstance : inventoryMovementTypeInstance ] }
+    }
+
+    def delete = {
+        def inventoryMovementTypeInstance = InventoryMovementType.get( params.id )
+        if(inventoryMovementTypeInstance) {
+            try {
+                inventoryMovementTypeInstance.delete(flush:true)
+                flash.message = "InventoryMovementType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "InventoryMovementType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "InventoryMovementType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def inventoryMovementTypeInstance = InventoryMovementType.get( params.id )
+
+        if(!inventoryMovementTypeInstance) {
+            flash.message = "InventoryMovementType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ inventoryMovementTypeInstance : inventoryMovementTypeInstance ]
+        }
+    }
+
+    def update = {
+        def inventoryMovementTypeInstance = InventoryMovementType.get( params.id )
+        if(inventoryMovementTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(inventoryMovementTypeInstance.version > version) {
+                    
+                    inventoryMovementTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[inventoryMovementTypeInstance:inventoryMovementTypeInstance])
+                    return
+                }
+            }
+            inventoryMovementTypeInstance.properties = params
+            if(!inventoryMovementTypeInstance.hasErrors() && inventoryMovementTypeInstance.save(flush: true)) {
+                flash.message = "InventoryMovementType ${params.id} updated"
+                redirect(action:show,id:inventoryMovementTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[inventoryMovementTypeInstance:inventoryMovementTypeInstance])
+            }
+        }
+        else {
+            flash.message = "InventoryMovementType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def inventoryMovementTypeInstance = new InventoryMovementType()
+        inventoryMovementTypeInstance.properties = params
+        return ['inventoryMovementTypeInstance':inventoryMovementTypeInstance]
+    }
+
+    def save = {
+        def inventoryMovementTypeInstance = new InventoryMovementType(params)
+        if(!inventoryMovementTypeInstance.hasErrors() && inventoryMovementTypeInstance.save(flush: true)) {
+            flash.message = "InventoryMovementType ${inventoryMovementTypeInstance.id} created"
+            redirect(action:show,id:inventoryMovementTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[inventoryMovementTypeInstance:inventoryMovementTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryStoreDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryStoreDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryStoreDetailedController.groovy	(revision 875)
@@ -0,0 +1,112 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+class InventoryStoreDetailedController extends BaseController {
+    
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ inventoryStoreInstanceList: InventoryStore.list( params ), inventoryStoreInstanceTotal: InventoryStore.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def inventoryStoreInstance = InventoryStore.get( params.id )
+
+        if(!inventoryStoreInstance) {
+            flash.message = "InventoryStore not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ inventoryStoreInstance : inventoryStoreInstance ] }
+    }
+
+    def delete = {
+        def inventoryStoreInstance = InventoryStore.get( params.id )
+        if(inventoryStoreInstance) {
+            try {
+                inventoryStoreInstance.delete(flush:true)
+                flash.message = "InventoryStore ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "InventoryStore ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "InventoryStore not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def inventoryStoreInstance = InventoryStore.get( params.id )
+
+        if(!inventoryStoreInstance) {
+            flash.message = "InventoryStore not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ inventoryStoreInstance : inventoryStoreInstance ]
+        }
+    }
+
+    def update = {
+        def inventoryStoreInstance = InventoryStore.get( params.id )
+        if(inventoryStoreInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(inventoryStoreInstance.version > version) {
+                    
+                    inventoryStoreInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[inventoryStoreInstance:inventoryStoreInstance])
+                    return
+                }
+            }
+            inventoryStoreInstance.properties = params
+            if(!inventoryStoreInstance.hasErrors() && inventoryStoreInstance.save(flush: true)) {
+                flash.message = "InventoryStore ${params.id} updated"
+                redirect(action:show,id:inventoryStoreInstance.id)
+            }
+            else {
+                render(view:'edit',model:[inventoryStoreInstance:inventoryStoreInstance])
+            }
+        }
+        else {
+            flash.message = "InventoryStore not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def inventoryStoreInstance = new InventoryStore()
+        inventoryStoreInstance.properties = params
+        return ['inventoryStoreInstance':inventoryStoreInstance]
+    }
+
+    def save = {
+        def inventoryStoreInstance = new InventoryStore(params)
+        if(!inventoryStoreInstance.hasErrors() && inventoryStoreInstance.save(flush: true)) {
+            flash.message = "InventoryStore ${inventoryStoreInstance.id} created"
+            redirect(action:show,id:inventoryStoreInstance.id)
+        }
+        else {
+            render(view:'create',model:[inventoryStoreInstance:inventoryStoreInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/InventoryTypeController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/InventoryTypeController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/InventoryTypeController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class InventoryTypeController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ inventoryTypeInstanceList: InventoryType.list( params ), inventoryTypeInstanceTotal: InventoryType.count() ]
+    }
+
+    def show = {
+        def inventoryTypeInstance = InventoryType.get( params.id )
+
+        if(!inventoryTypeInstance) {
+            flash.message = "InventoryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ inventoryTypeInstance : inventoryTypeInstance ] }
+    }
+
+    def delete = {
+        def inventoryTypeInstance = InventoryType.get( params.id )
+        if(inventoryTypeInstance) {
+            try {
+                inventoryTypeInstance.delete(flush:true)
+                flash.message = "InventoryType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "InventoryType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "InventoryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def inventoryTypeInstance = InventoryType.get( params.id )
+
+        if(!inventoryTypeInstance) {
+            flash.message = "InventoryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ inventoryTypeInstance : inventoryTypeInstance ]
+        }
+    }
+
+    def update = {
+        def inventoryTypeInstance = InventoryType.get( params.id )
+        if(inventoryTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(inventoryTypeInstance.version > version) {
+                    
+                    inventoryTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[inventoryTypeInstance:inventoryTypeInstance])
+                    return
+                }
+            }
+            inventoryTypeInstance.properties = params
+            if(!inventoryTypeInstance.hasErrors() && inventoryTypeInstance.save(flush: true)) {
+                flash.message = "InventoryType ${params.id} updated"
+                redirect(action:show,id:inventoryTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[inventoryTypeInstance:inventoryTypeInstance])
+            }
+        }
+        else {
+            flash.message = "InventoryType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def inventoryTypeInstance = new InventoryType()
+        inventoryTypeInstance.properties = params
+        return ['inventoryTypeInstance':inventoryTypeInstance]
+    }
+
+    def save = {
+        def inventoryTypeInstance = new InventoryType(params)
+        if(!inventoryTypeInstance.hasErrors() && inventoryTypeInstance.save(flush: true)) {
+            flash.message = "InventoryType ${inventoryTypeInstance.id} created"
+            redirect(action:show,id:inventoryTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[inventoryTypeInstance:inventoryTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/LoginController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/LoginController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/LoginController.groovy	(revision 875)
@@ -0,0 +1,188 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.RedirectUtils
+import org.grails.plugins.springsecurity.service.AuthenticateService
+
+import org.springframework.security.AuthenticationTrustResolverImpl
+import org.springframework.security.DisabledException
+import org.springframework.security.context.SecurityContextHolder as SCH
+import org.springframework.security.ui.AbstractProcessingFilter
+import org.springframework.security.ui.webapp.AuthenticationProcessingFilter
+
+/**
+ * Login Controller (Example).
+ */
+class LoginController {
+
+    /**
+    * Dependency injection for the authentication service.
+    */
+    def authenticateService
+
+    /**
+        * Dependency injection for OpenIDConsumer.
+        */
+    def openIDConsumer
+
+    /**
+    * Dependency injection for OpenIDAuthenticationProcessingFilter.
+    */
+    def openIDAuthenticationProcessingFilter
+
+    private final authenticationTrustResolver = new AuthenticationTrustResolverImpl()
+
+    def index = {
+        if (isLoggedIn()) {
+            redirect uri: '/'
+        }
+        else {
+            redirect action: auth, params: params
+        }
+    }
+
+    def loggedOut = {
+        flash['message'] = 'Successfully logged out'
+        auth()
+    }
+
+    /**
+    * Show the login page.
+    */
+    def auth = {
+
+        nocache(response)
+
+        if (isLoggedIn()) {
+            redirect uri: '/'
+            return
+        }
+
+        String view
+        String postUrl
+        def config = authenticateService.securityConfig.security
+        if (config.useOpenId) {
+            view = 'openIdAuth'
+            postUrl = "${request.contextPath}/login/openIdAuthenticate"
+        }
+        else if (config.useFacebook) {
+            view = 'facebookAuth'
+            postUrl = "${request.contextPath}${config.facebook.filterProcessesUrl}"
+        }
+        else {
+            view = 'auth'
+            postUrl = "${request.contextPath}${config.filterProcessesUrl}"
+        }
+
+        render view: view, model: [postUrl: postUrl]
+    }
+
+    /**
+    * Form submit action to start an OpenID authentication.
+    */
+    def openIdAuthenticate = {
+        String openID = params['j_username']
+        try {
+            String returnToURL = RedirectUtils.buildRedirectUrl(
+                    request, response, openIDAuthenticationProcessingFilter.filterProcessesUrl)
+            String redirectUrl = openIDConsumer.beginConsumption(request, openID, returnToURL)
+            redirect url: redirectUrl
+        }
+        catch (org.springframework.security.ui.openid.OpenIDConsumerException e) {
+            log.error "Consumer error: $e.message", e
+            redirect url: openIDAuthenticationProcessingFilter.authenticationFailureUrl
+        }
+    }
+
+    // Login page (function|json) for Ajax access.
+    def authAjax = {
+        nocache(response)
+        //this is example:
+        render """
+        <script type='text/javascript'>
+        (function() {
+            loginForm();
+        })();
+        </script>
+        """
+    }
+
+    /**
+    * The Ajax success redirect url.
+    */
+    def ajaxSuccess = {
+        nocache(response)
+        render '{success: true}'
+    }
+
+    /**
+    * Show denied page.
+    */
+    def denied = {
+        if (isLoggedIn() && authenticationTrustResolver.isRememberMe(SCH.context?.authentication)) {
+            // have cookie but the page is guarded with IS_AUTHENTICATED_FULLY
+            redirect action: full, params: params
+        }
+    }
+
+    /**
+    * Login page for users with a remember-me cookie but accessing a IS_AUTHENTICATED_FULLY page.
+    */
+    def full = {
+        render view: 'auth', params: params,
+            model: [hasCookie: authenticationTrustResolver.isRememberMe(SCH.context?.authentication)]
+    }
+
+    // Denial page (data|view|json) for Ajax access.
+    def deniedAjax = {
+        //this is example:
+        render "{error: 'access denied'}"
+    }
+
+    /**
+    * login failed
+    */
+    def authfail = {
+
+        def username = session[AuthenticationProcessingFilter.SPRING_SECURITY_LAST_USERNAME_KEY]
+        def msg = ''
+        def person = Person.findByLoginName(username)
+        def exception = session[AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY]
+        if (exception) {
+            if (exception instanceof DisabledException) {
+                msg = "[$username] is disabled."
+            }
+            else if (person?.authorities?.isEmpty()) {
+                msg = "[$username] has no granted authority."
+            }
+            else {
+                msg = "[$username] wrong username/password."
+            }
+        }
+
+        if (isAjax()) {
+            render "{error: '${msg}'}"
+        }
+        else {
+            flash.message = msg
+            redirect action: auth, params: params
+        }
+    }
+
+    /**
+    * Check if logged in.
+    */
+    private boolean isLoggedIn() {
+        return authenticateService.isLoggedIn()
+    }
+
+    private boolean isAjax() {
+        return authenticateService.isAjax(request)
+    }
+
+    /** cache controls */
+    private void nocache(response) {
+        response.setHeader('Cache-Control', 'no-cache') // HTTP 1.1
+        response.addDateHeader('Expires', 0)
+        response.setDateHeader('max-age', 0)
+        response.setIntHeader ('Expires', -1) //prevents caching at the proxy server
+        response.addHeader('cache-Control', 'private') //IE5.x only
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/LogoutController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/LogoutController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/LogoutController.groovy	(revision 875)
@@ -0,0 +1,14 @@
+/**
+ * Logout Controller (Example).
+ */
+class LogoutController {
+
+	/**
+	 * Index action. Redirects to the Spring security logout uri.
+	 */
+	def index = {
+		// TODO  put any pre-logout code here
+        
+		redirect(uri: '/j_spring_security_logout?logoutSuccessUrl=/login/loggedOut')
+	}
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/MaintenancePolicyDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/MaintenancePolicyDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/MaintenancePolicyDetailedController.groovy	(revision 875)
@@ -0,0 +1,113 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class MaintenancePolicyDetailedController extends BaseController {
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ maintenancePolicyInstanceList: MaintenancePolicy.list( params ), maintenancePolicyInstanceTotal: MaintenancePolicy.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def maintenancePolicyInstance = MaintenancePolicy.get( params.id )
+
+        if(!maintenancePolicyInstance) {
+            flash.message = "MaintenancePolicy not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ maintenancePolicyInstance : maintenancePolicyInstance ] }
+    }
+
+    def delete = {
+        def maintenancePolicyInstance = MaintenancePolicy.get( params.id )
+        if(maintenancePolicyInstance) {
+            try {
+                maintenancePolicyInstance.delete(flush:true)
+                flash.message = "MaintenancePolicy ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "MaintenancePolicy ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "MaintenancePolicy not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def maintenancePolicyInstance = MaintenancePolicy.get( params.id )
+
+        if(!maintenancePolicyInstance) {
+            flash.message = "MaintenancePolicy not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ maintenancePolicyInstance : maintenancePolicyInstance ]
+        }
+    }
+
+    def update = {
+        def maintenancePolicyInstance = MaintenancePolicy.get( params.id )
+        if(maintenancePolicyInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(maintenancePolicyInstance.version > version) {
+                    
+                    maintenancePolicyInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[maintenancePolicyInstance:maintenancePolicyInstance])
+                    return
+                }
+            }
+            maintenancePolicyInstance.properties = params
+            if(!maintenancePolicyInstance.hasErrors() && maintenancePolicyInstance.save(flush: true)) {
+                flash.message = "MaintenancePolicy ${params.id} updated"
+                redirect(action:show,id:maintenancePolicyInstance.id)
+            }
+            else {
+                render(view:'edit',model:[maintenancePolicyInstance:maintenancePolicyInstance])
+            }
+        }
+        else {
+            flash.message = "MaintenancePolicy not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def maintenancePolicyInstance = new MaintenancePolicy()
+        maintenancePolicyInstance.properties = params
+        return ['maintenancePolicyInstance':maintenancePolicyInstance]
+    }
+
+    def save = {
+        def maintenancePolicyInstance = new MaintenancePolicy(params)
+        if(!maintenancePolicyInstance.hasErrors() && maintenancePolicyInstance.save(flush: true)) {
+            flash.message = "MaintenancePolicy ${maintenancePolicyInstance.id} created"
+            redirect(action:show,id:maintenancePolicyInstance.id)
+        }
+        else {
+            render(view:'create',model:[maintenancePolicyInstance:maintenancePolicyInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/PeriodController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/PeriodController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/PeriodController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class PeriodController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ periodInstanceList: Period.list( params ), periodInstanceTotal: Period.count() ]
+    }
+
+    def show = {
+        def periodInstance = Period.get( params.id )
+
+        if(!periodInstance) {
+            flash.message = "Period not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ periodInstance : periodInstance ] }
+    }
+
+    def delete = {
+        def periodInstance = Period.get( params.id )
+        if(periodInstance) {
+            try {
+                periodInstance.delete(flush:true)
+                flash.message = "Period ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "Period ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "Period not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def periodInstance = Period.get( params.id )
+
+        if(!periodInstance) {
+            flash.message = "Period not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ periodInstance : periodInstance ]
+        }
+    }
+
+    def update = {
+        def periodInstance = Period.get( params.id )
+        if(periodInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(periodInstance.version > version) {
+                    
+                    periodInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[periodInstance:periodInstance])
+                    return
+                }
+            }
+            periodInstance.properties = params
+            if(!periodInstance.hasErrors() && periodInstance.save(flush: true)) {
+                flash.message = "Period ${params.id} updated"
+                redirect(action:show,id:periodInstance.id)
+            }
+            else {
+                render(view:'edit',model:[periodInstance:periodInstance])
+            }
+        }
+        else {
+            flash.message = "Period not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def periodInstance = new Period()
+        periodInstance.properties = params
+        return ['periodInstance':periodInstance]
+    }
+
+    def save = {
+        def periodInstance = new Period(params)
+        if(!periodInstance.hasErrors() && periodInstance.save(flush: true)) {
+            flash.message = "Period ${periodInstance.id} created"
+            redirect(action:show,id:periodInstance.id)
+        }
+        else {
+            render(view:'create',model:[periodInstance:periodInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/PersonController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/PersonController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/PersonController.groovy	(revision 875)
@@ -0,0 +1,282 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class PersonController extends BaseAppAdminController {
+
+    def filterService
+    def personCsvService
+    def authenticateService
+
+    // the delete, save and update actions only accept POST requests
+    static Map allowedMethods = [delete: 'POST', save: 'POST', update: 'POST']
+
+    def index = {
+        redirect action: list, params: params
+    }
+
+    /**
+    * Disaply the import view.
+    */
+    def importPersons = {
+    }
+
+    /**
+    * Handle the import save.
+    */
+    def importPersonsSave = {
+        def result = personCsvService.importPersons(request)
+
+        if(!result.error) {
+            response.contentType = ConfigurationHolder.config.grails.mime.types["text"]
+            response.setHeader("Content-disposition", "attachment; filename=LoginNamesAndPasswords.txt")
+            render result.loginNamesAndPasswords
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: importPersons)
+    }
+
+    /**
+    * Export a csv template.
+    * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time!
+    * This does not appear to be a problem once deployed to Tomcat.
+    */
+    def exportPersonsTemplate = {
+        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
+        response.setHeader("Content-disposition", "attachment; filename=personsTemplate.csv")
+        def s = personCsvService.buildPersonsTemplate()
+        render s
+    }
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100 )
+
+        if(!params.filter) {
+            return [personList: Person.list(params),
+                            personTotal: Person.count(),
+                            filterParams: params]
+        }
+
+        // filterPane:
+        return[ personList: filterService.filter( params, Person ),
+            personTotal: filterService.count( params, Person ),
+            filterParams: com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params),
+            params:params ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def person = Person.get(params.id)
+        if (!person) {
+            flash.message = "Person not found with id $params.id"
+            redirect action: list
+            return
+        }
+        def authorityList = person.authorities.sort { p1, p2 -> p1.id <=> p2.id }
+        [person: person, authorityList: authorityList]
+    }
+
+    /**
+    * Person delete action. Before removing an existing person,
+    * they should be removed from those authorities which they are involved.
+    */
+    def delete = {
+
+        def person = Person.get(params.id)
+        if (person) {
+            def authPrincipal = authenticateService.principal()
+            // Avoid self-delete.
+            if (!(authPrincipal instanceof String) && authPrincipal.username == person.loginName) {
+                flash.errorMessage = "You cannot delete yourself, please login as another manager and try again."
+                redirect(action:show,id:params.id)
+            }
+            else if ( person.id == 1L) {
+                flash.errorMessage = "You cannot delete the pseudo system person."
+                redirect(action:show,id:params.id)
+            }
+            else if ( person.id == 2L) {
+                flash.errorMessage = "You cannot delete the admin person."
+                redirect(action:show,id:params.id)
+            }
+            else {
+                //first, delete this person from Persons_Authorities table.
+                Authority.findAll().each { it.removeFromPersons(person) }
+                person.isActive = false
+                person.save(flush: true)
+
+                try {
+                    person.delete(flush: true)
+                    flash.message = "Person $params.id deleted."
+                    redirect(action:list)
+                }
+                catch(org.springframework.dao.DataIntegrityViolationException e) {
+                    flash.message = "Could not delete '$person.loginName' due to database constraints, but all authorities have been removed."
+                    redirect(action:show,id:params.id)
+                }
+            }
+        }
+        else {
+            flash.errorMessage = "Person not found with id $params.id"
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def person = Person.get(params.id)
+        if (!person) {
+            flash.message = "Person not found with id $params.id"
+            redirect action: list
+            return
+        }
+
+        if ( person.id == 1L) {
+            flash.errorMessage = "You cannot edit the pseudo system person."
+            redirect(action:show,id:params.id)
+            return
+        }
+
+        params.message = "To allow login at least the 'ROLE_AppUser' authority must be given."
+        return buildPersonModel(person)
+    }
+
+    /**
+    * Person update action.
+    */
+    def update = {
+        Person.withTransaction { status ->
+
+            def person = Person.get(params.id)
+            if (!person) {
+                flash.message = "Person not found with id $params.id"
+                redirect action: edit, id: params.id
+                return
+            }
+
+            long version = params.version.toLong()
+            if (person.version > version) {
+                person.errors.rejectValue 'version', "default.optimistic.locking.failure"
+                render view: 'edit', model: buildPersonModel(person)
+                return
+            }
+
+            if ( person.id == 1L) {
+                flash.errorMessage = "You cannot edit the pseudo system person."
+                redirect(action:show,id:params.id)
+                return
+            }
+
+            person.properties = params
+            person.setPersonGroupsFromCheckBoxList(params.personGroups)
+            person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups)
+
+            if(params.pass == "") {
+                person.pass = "InsertNothingToClearValidation"
+            }
+            else {
+                if (person.validate()) {
+                    person.password = authenticateService.encodePassword(params.pass)
+                }
+            }
+
+            if (!person.hasErrors() && person.save(flush: true)) {
+                addRemoveAuthorities(person)
+                flash.message = "Person '$params.id - $params.loginName' updated."
+                redirect action: show, id: person.id
+            }
+            else {
+                render view: 'edit', model: buildPersonModel(person)
+            }
+
+        } //end withTransaction
+    } // update()
+
+    def create = {
+        params.message = "To allow login at least the 'ROLE_AppUser' authority must be given."
+        [person: new Person(params), authorityList: getLimitedAuthorityList()]
+    }
+
+    /**
+    * Person save action.
+    */
+    def save = {
+        Person.withTransaction { status ->
+
+            def person = new Person()
+            person.properties = params
+            person.password = authenticateService.encodePassword(params.pass)
+            person.setPersonGroupsFromCheckBoxList(params.personGroups)
+            person.setPurchasingGroupsFromCheckBoxList(params.purchasingGroups)
+            if (person.save(flush: true)) {
+                addRemoveAuthorities(person)
+                redirect action: show, id: person.id
+            }
+            else {
+                render view: 'create', model: [person: person, authorityList: getLimitedAuthorityList()]
+            }
+
+        } //end withTransaction
+    }
+
+    /**
+    * Add or remove authorities from person as indicated in params.
+    */
+    private void addRemoveAuthorities(person) {
+        def authMap = [:]
+
+        // Build authMap from params.
+        for (key in params.keySet()) {
+            if(key.startsWith("ROLE")) {
+                authMap.(key.toString()) = "add"
+            }
+            else if(key.startsWith("_ROLE")) {
+                if( !authMap.(key.substring(1)) ) authMap.(key.substring(1)) = "remove"
+            }
+        }
+
+        // Add or remove authorities.
+        for(a in authMap) {
+            if(a.value == "add")
+                Authority.findByAuthority(a.key.toString()).addToPersons(person)
+            else
+                Authority.findByAuthority(a.key.toString()).removeFromPersons(person)
+        }
+    }
+
+    private Map buildPersonModel(person) {
+
+        List roles = getLimitedAuthorityList()
+        Set userRoleNames = []
+        for (role in person.authorities) {
+            userRoleNames << role.authority
+        }
+        LinkedHashMap<Authority, Boolean> roleMap = [:]
+        for (role in roles) {
+            roleMap[(role)] = userRoleNames.contains(role.authority)
+        }
+
+        return [person: person, roleMap: roleMap]
+    }
+
+    /**
+    * Get the full authorityList if current user is an App Admin else leave that authority off the list.
+    */
+    private List getLimitedAuthorityList() {
+        def authorityList = []
+        if(authenticateService.ifAnyGranted('ROLE_AppAdmin'))
+            authorityList = Authority.list().sort { p1, p2 -> p1.id <=> p2.id }
+        else
+            authorityList = Authority.withCriteria { gt("id", 1L) }.sort { p1, p2 -> p1.id <=> p2.id }
+
+        return authorityList
+    }
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/controllers/PersonGroupDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/PersonGroupDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/PersonGroupDetailedController.groovy	(revision 875)
@@ -0,0 +1,100 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class PersonGroupDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ personGroupInstanceList: PersonGroup.list( params ), personGroupInstanceTotal: PersonGroup.count() ]
+    }
+
+    def show = {
+        def personGroupInstance = PersonGroup.get( params.id )
+
+        if(!personGroupInstance) {
+            flash.message = "PersonGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ personGroupInstance : personGroupInstance ] }
+    }
+
+    def delete = {
+        def personGroupInstance = PersonGroup.get( params.id )
+        if(personGroupInstance) {
+            try {
+                personGroupInstance.delete(flush:true)
+                flash.message = "PersonGroup ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "PersonGroup ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "PersonGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def personGroupInstance = PersonGroup.get( params.id )
+
+        if(!personGroupInstance) {
+            flash.message = "PersonGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ personGroupInstance : personGroupInstance ]
+        }
+    }
+
+    def update = {
+        def personGroupInstance = PersonGroup.get( params.id )
+        if(personGroupInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(personGroupInstance.version > version) {
+                    
+                    personGroupInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[personGroupInstance:personGroupInstance])
+                    return
+                }
+            }
+            personGroupInstance.properties = params
+            if(!personGroupInstance.hasErrors() && personGroupInstance.save(flush: true)) {
+                flash.message = "PersonGroup ${params.id} updated"
+                redirect(action:show,id:personGroupInstance.id)
+            }
+            else {
+                render(view:'edit',model:[personGroupInstance:personGroupInstance])
+            }
+        }
+        else {
+            flash.message = "PersonGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def personGroupInstance = new PersonGroup()
+        personGroupInstance.properties = params
+        return ['personGroupInstance':personGroupInstance]
+    }
+
+    def save = {
+        def personGroupInstance = new PersonGroup(params)
+        if(!personGroupInstance.hasErrors() && personGroupInstance.save(flush: true)) {
+            flash.message = "PersonGroup ${personGroupInstance.id} created"
+            redirect(action:show,id:personGroupInstance.id)
+        }
+        else {
+            render(view:'create',model:[personGroupInstance:personGroupInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/PersonGroupTypeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/PersonGroupTypeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/PersonGroupTypeDetailedController.groovy	(revision 875)
@@ -0,0 +1,100 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class PersonGroupTypeDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ personGroupTypeInstanceList: PersonGroupType.list( params ), personGroupTypeInstanceTotal: PersonGroupType.count() ]
+    }
+
+    def show = {
+        def personGroupTypeInstance = PersonGroupType.get( params.id )
+
+        if(!personGroupTypeInstance) {
+            flash.message = "PersonGroupType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ personGroupTypeInstance : personGroupTypeInstance ] }
+    }
+
+    def delete = {
+        def personGroupTypeInstance = PersonGroupType.get( params.id )
+        if(personGroupTypeInstance) {
+            try {
+                personGroupTypeInstance.delete(flush:true)
+                flash.message = "PersonGroupType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "PersonGroupType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "PersonGroupType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def personGroupTypeInstance = PersonGroupType.get( params.id )
+
+        if(!personGroupTypeInstance) {
+            flash.message = "PersonGroupType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ personGroupTypeInstance : personGroupTypeInstance ]
+        }
+    }
+
+    def update = {
+        def personGroupTypeInstance = PersonGroupType.get( params.id )
+        if(personGroupTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(personGroupTypeInstance.version > version) {
+                    
+                    personGroupTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[personGroupTypeInstance:personGroupTypeInstance])
+                    return
+                }
+            }
+            personGroupTypeInstance.properties = params
+            if(!personGroupTypeInstance.hasErrors() && personGroupTypeInstance.save(flush: true)) {
+                flash.message = "PersonGroupType ${params.id} updated"
+                redirect(action:show,id:personGroupTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[personGroupTypeInstance:personGroupTypeInstance])
+            }
+        }
+        else {
+            flash.message = "PersonGroupType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def personGroupTypeInstance = new PersonGroupType()
+        personGroupTypeInstance.properties = params
+        return ['personGroupTypeInstance':personGroupTypeInstance]
+    }
+
+    def save = {
+        def personGroupTypeInstance = new PersonGroupType(params)
+        if(!personGroupTypeInstance.hasErrors() && personGroupTypeInstance.save(flush: true)) {
+            flash.message = "PersonGroupType ${personGroupTypeInstance.id} created"
+            redirect(action:show,id:personGroupTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[personGroupTypeInstance:personGroupTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/PictureDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/PictureDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/PictureDetailedController.groovy	(revision 875)
@@ -0,0 +1,215 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
+class PictureDetailedController extends BaseController {
+
+    def index = { redirect(action:list, params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        prepareList()
+        [ list: Picture.list(params), paginateCount: Picture.count() ]
+    }
+
+    void prepareList() {
+        if (!params.max) {
+            params.max = 10
+        }
+        if (!params.order) {
+            params.order = "desc"
+        }
+        if (!params.sort) {
+            params.sort = "id"
+        }
+    }
+
+    def show = {
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def picture = Picture.get( params.id )
+
+        if(!picture) {
+            flash.message = "Picture not found."
+            redirect(action:list)
+        }
+        else { [ picture : picture ] }
+    }
+
+    def delete = {
+        def picture = Picture.get(params.id)
+        def inventoryItem = InventoryItem.get(picture?.inventoryItem?.id)
+
+        if (inventoryItem && picture) {
+            Picture.withTransaction { status ->
+                inventoryItem.picture = null
+                inventoryItem.save()
+                picture.delete()
+            }
+            flash.message = "Picture ${params.id} deleted"
+            redirect(controller: "inventoryItemDetailed", action: show, id: inventoryItem.id)
+
+        }
+        else {
+            if(picture) {
+                flash.message = "Removing orphan picture ${picture.id}."
+                picture.delete(flush:true)
+                redirect(action: list)
+            }
+            else {
+                flash.message = "Picture not found"
+                redirect(action: list)
+            }
+        }
+    }
+
+    def edit = {
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def picture = Picture.get(params.id)
+        if (!picture) {
+            flash.message = "Picture not found"
+            redirect(action: list)
+        }
+        else {
+            [ picture : picture ]
+        }
+    }
+
+    def update = {
+        def picture = Picture.get(params.id)
+        def inventoryItem = picture?.inventoryItem
+        if (inventoryItem && picture) {
+
+            if(params.version) {
+                def version = params.version.toLong()
+                if(picture.version > version) {
+                    picture.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[picture:picture])
+                    return
+                }
+            }
+
+            picture.properties = params
+            if (!picture.hasErrors()) {
+                def imaging = new Imaging()
+                def images = imaging.updateAll(picture)
+                boolean result = false
+                Picture.withTransaction{ status ->
+                    result = picture.save()
+                }
+                if (result) {
+                    flash.message = "Picture ${params.id} updated"
+                    redirect(action: show, id: picture.id)
+                }
+                else {
+                    render(view: 'edit', model: [ picture: picture ])
+                }
+            }
+            else {
+                render(view: 'edit', model: [ picture: picture ])
+            }
+        }
+        else {
+            flash.message = "Picture not updated, picture or inventory item not found."
+            redirect(action: list)
+        }
+    }
+
+    def create = {
+        if(!params.inventoryItem?.id) {
+            flash.message = "Please select an inventory item and then 'Add Picture'."
+            redirect(controller: "inventoryItemDetailed", action: 'search')
+            return
+        }
+        def picture = new Picture()
+        picture.properties = params
+        [ picture: picture ]
+    }
+
+    def save = {
+        def inventoryItem = InventoryItem.get(params.inventoryItem.id)
+        if (inventoryItem) {
+            if(inventoryItem.picture) {
+                flash.message = "Inventory item already has a picture, please delete the old picture first."
+                redirect(controller: 'inventoryItemDetailed', action: 'show', id: inventoryItem.id)
+                return
+            }
+            def picture = new Picture(params)
+            def multiPartFile = request.getFile('file')
+            def imaging = new Imaging()
+            def images = null
+            if (multiPartFile && !multiPartFile.isEmpty()) {
+                if (multiPartFile.getSize() > Image.MAX_SIZE) {
+                    picture.errors.rejectValue('file', 'picture.file.maxSize.exceeded',
+                        [ 'file', 'Picture', Image.MAX_SIZE ] as Object[],
+                        'Property [{0}] of class [{1}] image file is too big (maximum [{2}] bytes)')
+                }
+                else {
+                    try {
+                        images = imaging.createAll(inventoryItem, picture, multiPartFile.inputStream)
+                    }
+                    catch(Exception ex) {
+                        log.error("picture save", ex)
+                        picture.errors.rejectValue('file', 'picture.file.unrecognised',
+                            [ 'file', 'Picture', multiPartFile.originalFilename ] as Object[],
+                            'Property [{0}] of class [{1}] image file [{2}]: type not recognised')
+                    }
+                }
+            }
+            else {
+                picture.errors.rejectValue('file', 'picture.file.missing',
+                    ['file', 'Picture', ''] as Object[],
+                    'Property [{0}] of class [{1}] no file specified')
+            }
+            if (images && !picture.hasErrors()) {
+                boolean result = false
+                Picture.withTransaction { status ->
+                    images.each { image ->
+                        picture.addToImages(image)
+                    }
+                    result = picture.save()
+                    inventoryItem.picture = picture
+                    inventoryItem.save()
+                }
+                if (result) {
+                    flash.message = "Picture ${picture.id} created"
+                    redirect(controller: 'inventoryItemDetailed', action: 'show', id: inventoryItem.id)
+                }
+                else {
+                    render(view: 'create', model: [ picture: picture ])
+                }
+            }
+            else {
+                render(view: 'create', model: [ picture: picture ])
+            }
+        }
+        else {
+            flash.message = "Picture not created, inventory item not found."
+            redirect(action: list)
+        }
+    }
+
+    def view = {
+        def picture = Picture.get(params.id)
+        def size = params.size ? Integer.parseInt(params.size) : Image.Small
+        def image = picture ? Image.findByPictureAndSize(picture, size) : null
+        if (picture && image) {
+            response.setContentType(image.contentType)
+            response.setContentLength(image.data.size())
+            response.setHeader('filename', image.filename())
+            OutputStream out = response.outputStream
+            out.write(image.data)
+            out.close()
+        }
+        else {
+            response.sendError(404)
+        }
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/ProductionReferenceDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/ProductionReferenceDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/ProductionReferenceDetailedController.groovy	(revision 875)
@@ -0,0 +1,100 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_ProductionManager'])
+class ProductionReferenceDetailedController extends BaseController {
+
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ productionReferenceInstanceList: ProductionReference.list( params ), productionReferenceInstanceTotal: ProductionReference.count() ]
+    }
+
+    def show = {
+        def productionReferenceInstance = ProductionReference.get( params.id )
+
+        if(!productionReferenceInstance) {
+            flash.message = "ProductionReference not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ productionReferenceInstance : productionReferenceInstance ] }
+    }
+
+    def delete = {
+        def productionReferenceInstance = ProductionReference.get( params.id )
+        if(productionReferenceInstance) {
+            try {
+                productionReferenceInstance.delete(flush:true)
+                flash.message = "ProductionReference ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "ProductionReference ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "ProductionReference not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def productionReferenceInstance = ProductionReference.get( params.id )
+
+        if(!productionReferenceInstance) {
+            flash.message = "ProductionReference not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ productionReferenceInstance : productionReferenceInstance ]
+        }
+    }
+
+    def update = {
+        def productionReferenceInstance = ProductionReference.get( params.id )
+        if(productionReferenceInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(productionReferenceInstance.version > version) {
+                    
+                    productionReferenceInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[productionReferenceInstance:productionReferenceInstance])
+                    return
+                }
+            }
+            productionReferenceInstance.properties = params
+            if(!productionReferenceInstance.hasErrors() && productionReferenceInstance.save(flush: true)) {
+                flash.message = "ProductionReference ${params.id} updated"
+                redirect(action:show,id:productionReferenceInstance.id)
+            }
+            else {
+                render(view:'edit',model:[productionReferenceInstance:productionReferenceInstance])
+            }
+        }
+        else {
+            flash.message = "ProductionReference not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def productionReferenceInstance = new ProductionReference()
+        productionReferenceInstance.properties = params
+        return ['productionReferenceInstance':productionReferenceInstance]
+    }
+
+    def save = {
+        def productionReferenceInstance = new ProductionReference(params)
+        if(!productionReferenceInstance.hasErrors() && productionReferenceInstance.save(flush: true)) {
+            flash.message = "ProductionReference ${productionReferenceInstance.id} created"
+            redirect(action:show,id:productionReferenceInstance.id)
+        }
+        else {
+            render(view:'create',model:[productionReferenceInstance:productionReferenceInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/PurchasingGroupDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/PurchasingGroupDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/PurchasingGroupDetailedController.groovy	(revision 875)
@@ -0,0 +1,110 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager'])
+class PurchasingGroupDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ purchasingGroupInstanceList: PurchasingGroup.list( params ), purchasingGroupInstanceTotal: PurchasingGroup.count() ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+
+        if(!purchasingGroupInstance) {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ purchasingGroupInstance : purchasingGroupInstance ] }
+    }
+
+    def delete = {
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+        if(purchasingGroupInstance) {
+            try {
+                purchasingGroupInstance.delete(flush:true)
+                flash.message = "PurchasingGroup ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "PurchasingGroup ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+
+        if(!purchasingGroupInstance) {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ purchasingGroupInstance : purchasingGroupInstance ]
+        }
+    }
+
+    def update = {
+        def purchasingGroupInstance = PurchasingGroup.get( params.id )
+        if(purchasingGroupInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(purchasingGroupInstance.version > version) {
+                    
+                    purchasingGroupInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[purchasingGroupInstance:purchasingGroupInstance])
+                    return
+                }
+            }
+            purchasingGroupInstance.properties = params
+            if(!purchasingGroupInstance.hasErrors() && purchasingGroupInstance.save(flush: true)) {
+                flash.message = "PurchasingGroup ${params.id} updated"
+                redirect(action:show,id:purchasingGroupInstance.id)
+            }
+            else {
+                render(view:'edit',model:[purchasingGroupInstance:purchasingGroupInstance])
+            }
+        }
+        else {
+            flash.message = "PurchasingGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def purchasingGroupInstance = new PurchasingGroup()
+        purchasingGroupInstance.properties = params
+        return ['purchasingGroupInstance':purchasingGroupInstance]
+    }
+
+    def save = {
+        def purchasingGroupInstance = new PurchasingGroup(params)
+        if(!purchasingGroupInstance.hasErrors() && purchasingGroupInstance.save(flush: true)) {
+            flash.message = "PurchasingGroup ${purchasingGroupInstance.id} created"
+            redirect(action:show,id:purchasingGroupInstance.id)
+        }
+        else {
+            render(view:'create',model:[purchasingGroupInstance:purchasingGroupInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/ReportController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/ReportController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/ReportController.groovy	(revision 875)
@@ -0,0 +1,316 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import org.springframework.web.servlet.support.RequestContextUtils as RCU
+
+class ReportController extends BaseController {
+
+    def authService
+    def dateUtilService
+    def taskReportService
+    def assetReportService
+    def inventoryReportService
+
+    def index = { redirect(action:templatePortrait,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    //static allowedMethods = [list:'POST']
+
+    def templatePortrait = {
+
+        params.startDate = new Date()
+        params.endDate = new Date()
+
+        params.reportTitle = "Template Report (Portrait)"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        params.startDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: params.startDate)
+        params.endDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: params.endDate)
+
+        def dataModel = createTemplateData()
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    } // templatePortrait
+
+    def templateLandscape = {
+
+        params.startDate = new Date()
+        params.endDate = new Date()
+
+        params.reportTitle = "Template Report (Landscape)"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        params.startDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: params.startDate)
+        params.endDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: params.endDate)
+
+        def dataModel = createTemplateData()
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    } // templateLandscape
+
+    private createTemplateData() {
+
+        def result = [:]
+        result.summaryOfCalculationMethod = "Summary string of the calculations performed."
+        result.dataList = []
+        for(i in 1..5) {
+            def dataDetails = [:]
+            dataDetails.description = "Data description " + i.toString()
+            result.dataList << dataDetails
+        }
+
+        // Success.
+        return result
+
+    } // createTemplateData
+
+    def downloadTemplate = {
+
+        // params.fileName is not used directly to negate any security issues..
+        def fileName = (params.fileName == 'templateLandscape.jrxml') ? 'templateLandscape.jrxml' : 'templatePortrait.jrxml'
+        def f = grailsApplication.mainContext.getResource("reports/${fileName}").getFile()
+        if(f.isFile()) {
+            response.contentType = ConfigurationHolder.config.grails.mime.types["text"]
+            response.setHeader("Content-disposition", "attachment; filename=${fileName}")
+            render f.text
+        }
+        else
+            render(status:404, text: "File Not Found: ${f}")
+
+    } // downLoadTemplate
+
+    def reactiveRatio = {
+
+        def result = taskReportService.getReactiveRatio(params, RCU.getLocale(request))
+
+        params.reportTitle = "Reactive Ratio Report"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        params.startDateString = result.startDateString
+        params.endDateString = result.endDateString
+
+        if(!result.error) {
+            // Jasper plugin controller expects data to be a Collection.
+            chain(controller:'jasper', action:'index', model:[data: [result]], params:params)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(controller: 'appCore', action: 'start', params: [showTab:'showReportsTab'])
+
+    } // reactiveRatio
+
+    def immediateCallouts = {
+
+        def result = taskReportService.getImmediateCallouts(params, RCU.getLocale(request))
+
+        params.reportTitle = "Immediate Callouts"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        params.startDateString = result.startDateString
+        params.endDateString = result.endDateString
+
+        if(!result.error) {
+            // Jasper plugin controller expects data to be a Collection.
+            chain(controller:'jasper', action:'index', model:[data: [result]], params:params)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(controller: 'appCore', action: 'start', params: [showTab:'showReportsTab'])
+
+    } // immediateCallouts
+
+    def stockTakeOverview = {
+
+        params.reportTitle = "Stock Take Overview"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+
+        def dataModel = inventoryReportService.getStockTakeOverview(params, RCU.getLocale(request))
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    } // stockTakeOverview
+
+    def stockTakeByLocation = {
+
+        params.reportTitle = "Stock Take By Location"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+
+        def dataModel = inventoryReportService.getStockTakeByLocation(params, RCU.getLocale(request))
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    } // stockTakeByLocation
+
+    def assetDetail = {
+
+        params.reportTitle = "Asset Detail"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        if(params.section.id == 'all') {
+            params.section = "All"
+            params.site = "All"
+        }
+        else {
+            params.section = Section.get(params.section.id.toLong())
+            params.site = params.section.site
+        }
+
+        def dataModel = assetReportService.getAssetDetail(params, RCU.getLocale(request))
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: dataModel], params:params)
+
+    } // assetDetail
+
+    def assetRegister = {
+
+        params.reportTitle = "Asset Register"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+
+        def dataModel = assetReportService.getAssetRegister(params, RCU.getLocale(request))
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    } // assetRegister
+
+    def equipmentRegisterOhsGsp = {
+        render(view: 'equipmentRegisterOhs')
+    }
+
+    def equipmentRegisterOhs = {
+
+        params.calculateRegulatoryTaskCompletion = true
+        def result = assetReportService.getEquipmentRegister(params, RCU.getLocale(request))
+
+        params.reportTitle = "Equipment Register OH&S"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        params.startDateString = result.startDateString
+        params.endDateString = result.endDateString
+
+        if(!result.error) {
+            // Jasper plugin controller expects data to be a Collection.
+            chain(controller:'jasper', action:'index', model:[data: [result]], params:params)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: 'equipmentRegisterOhsGsp')
+
+//         render {
+//             dataModel.dataList.each {
+//                 p("$it")
+//             }
+//         }
+
+    } // equipmentRegisterOhs
+
+    def equipmentRegisterFinancial = {
+
+        params.reportTitle = "Equipment Register Financial"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+
+        def dataModel = assetReportService.getEquipmentRegister(params, RCU.getLocale(request))
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    } // equipmentRegisterFinancial
+
+    def inventoryValueDetailedGsp = {
+        render(view: 'inventoryValueDetailed')
+    }
+
+    def inventoryValueDetailed = {
+
+        params.reportTitle = "Inventory Value Detailed"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+
+        def dataModel = inventoryReportService.getInventoryValueDetailed(params, RCU.getLocale(request))
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    }
+
+    def inventoryValueOverviewGsp = {
+        render(view: 'inventoryValueOverview')
+    }
+
+    def inventoryValueOverview = {
+
+        params.reportTitle = "Inventory Value Overview"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+
+        def dataModel = inventoryReportService.getInventoryValueOverview(params, RCU.getLocale(request))
+
+        // Jasper plugin controller expects data to be a Collection.
+        chain(controller:'jasper', action:'index', model:[data: [dataModel]], params:params)
+
+    }
+
+    def regulatoryRequirementsGsp = {
+        render(view: 'regulatoryRequirements')
+    }
+
+    def regulatoryRequirements = {
+
+        def result = assetReportService.getRegulatoryRequirements(params, RCU.getLocale(request))
+
+        params.reportTitle = "Asset Regulatory Requirements"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        params.startDateString = result.startDateString
+        params.endDateString = result.endDateString
+
+        if(!result.error) {
+            // Jasper plugin controller expects data to be a Collection.
+            chain(controller:'jasper', action:'index', model:[data: [result]], params:params)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: 'regulatoryRequirementsGsp')
+
+    } // regulatoryRequirements
+
+    def mandatoryRequirementsGsp = {
+        render(view: 'mandatoryRequirements')
+    }
+
+    def mandatoryRequirements = {
+
+        def result = assetReportService.getMandatoryRequirements(params, RCU.getLocale(request))
+
+        params.reportTitle = "Asset Mandatory Requirements"
+        params.logoUrl = grailsApplication.mainContext.getResource('images/logo.png').getURL()
+        params.currentUser = authService.currentUser
+        params.startDateString = result.startDateString
+        params.endDateString = result.endDateString
+
+        if(!result.error) {
+            // Jasper plugin controller expects data to be a Collection.
+            chain(controller:'jasper', action:'index', model:[data: [result]], params:params)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+        redirect(action: 'mandatoryRequirementsGsp')
+
+    } // mandatoryRequirements
+
+} // end of class.
Index: /branches/features/grailsUpgrade/grails-app/controllers/SectionDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/SectionDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/SectionDetailedController.groovy	(revision 875)
@@ -0,0 +1,116 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class SectionDetailedController extends BaseController {
+
+    def sectionService
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def index = { redirect(action:list,params:params) }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ sectionInstanceList: Section.list( params ), sectionInstanceTotal: Section.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def sectionInstance = Section.get( params.id )
+
+        if(!sectionInstance) {
+            flash.message = "Section not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ sectionInstance : sectionInstance ] }
+    }
+
+    @Secured(['ROLE_AppAdmin'])
+    def delete = {
+        def result = sectionService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["Section", params.id])
+            redirect(action:list)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(action:list)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def sectionInstance = Section.get( params.id )
+
+        if(!sectionInstance) {
+            flash.message = "Section not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ sectionInstance : sectionInstance ]
+        }
+    }
+
+    def update = {
+        def sectionInstance = Section.get( params.id )
+        if(sectionInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(sectionInstance.version > version) {
+                    
+                    sectionInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[sectionInstance:sectionInstance])
+                    return
+                }
+            }
+            sectionInstance.properties = params
+            if(!sectionInstance.hasErrors() && sectionInstance.save(flush: true)) {
+                flash.message = "Section ${params.id} updated"
+                redirect(action:show,id:sectionInstance.id)
+            }
+            else {
+                render(view:'edit',model:[sectionInstance:sectionInstance])
+            }
+        }
+        else {
+            flash.message = "Section not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def sectionInstance = new Section()
+        sectionInstance.properties = params
+        return ['sectionInstance':sectionInstance]
+    }
+
+    def save = {
+        def sectionInstance = new Section(params)
+        if(!sectionInstance.hasErrors() && sectionInstance.save(flush: true)) {
+            flash.message = "Section ${sectionInstance.id} created"
+            redirect(action:show,id:sectionInstance.id)
+        }
+        else {
+            render(view:'create',model:[sectionInstance:sectionInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/SectionExtendedAttributeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/SectionExtendedAttributeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/SectionExtendedAttributeDetailedController.groovy	(revision 875)
@@ -0,0 +1,100 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class SectionExtendedAttributeDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ sectionExtendedAttributeInstanceList: SectionExtendedAttribute.list( params ), sectionExtendedAttributeInstanceTotal: SectionExtendedAttribute.count() ]
+    }
+
+    def show = {
+        def sectionExtendedAttributeInstance = SectionExtendedAttribute.get( params.id )
+
+        if(!sectionExtendedAttributeInstance) {
+            flash.message = "SectionExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ sectionExtendedAttributeInstance : sectionExtendedAttributeInstance ] }
+    }
+
+    def delete = {
+        def sectionExtendedAttributeInstance = SectionExtendedAttribute.get( params.id )
+        if(sectionExtendedAttributeInstance) {
+            try {
+                sectionExtendedAttributeInstance.delete(flush:true)
+                flash.message = "SectionExtendedAttribute ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "SectionExtendedAttribute ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "SectionExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def sectionExtendedAttributeInstance = SectionExtendedAttribute.get( params.id )
+
+        if(!sectionExtendedAttributeInstance) {
+            flash.message = "SectionExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ sectionExtendedAttributeInstance : sectionExtendedAttributeInstance ]
+        }
+    }
+
+    def update = {
+        def sectionExtendedAttributeInstance = SectionExtendedAttribute.get( params.id )
+        if(sectionExtendedAttributeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(sectionExtendedAttributeInstance.version > version) {
+                    
+                    sectionExtendedAttributeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[sectionExtendedAttributeInstance:sectionExtendedAttributeInstance])
+                    return
+                }
+            }
+            sectionExtendedAttributeInstance.properties = params
+            if(!sectionExtendedAttributeInstance.hasErrors() && sectionExtendedAttributeInstance.save(flush: true)) {
+                flash.message = "SectionExtendedAttribute ${params.id} updated"
+                redirect(action:show,id:sectionExtendedAttributeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[sectionExtendedAttributeInstance:sectionExtendedAttributeInstance])
+            }
+        }
+        else {
+            flash.message = "SectionExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def sectionExtendedAttributeInstance = new SectionExtendedAttribute()
+        sectionExtendedAttributeInstance.properties = params
+        return ['sectionExtendedAttributeInstance':sectionExtendedAttributeInstance]
+    }
+
+    def save = {
+        def sectionExtendedAttributeInstance = new SectionExtendedAttribute(params)
+        if(!sectionExtendedAttributeInstance.hasErrors() && sectionExtendedAttributeInstance.save(flush: true)) {
+            flash.message = "SectionExtendedAttribute ${sectionExtendedAttributeInstance.id} created"
+            redirect(action:show,id:sectionExtendedAttributeInstance.id)
+        }
+        else {
+            render(view:'create',model:[sectionExtendedAttributeInstance:sectionExtendedAttributeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/SiteDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/SiteDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/SiteDetailedController.groovy	(revision 875)
@@ -0,0 +1,116 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class SiteDetailedController extends BaseController {
+
+    def siteService
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def index = { redirect(action:list,params:params) }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ siteInstanceList: Site.list( params ), siteInstanceTotal: Site.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def siteInstance = Site.get( params.id )
+
+        if(!siteInstance) {
+            flash.message = "Site not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ siteInstance : siteInstance ] }
+    }
+
+    @Secured(['ROLE_AppAdmin'])
+    def delete = {
+        def result = siteService.delete(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.delete.success", args: ["Site", params.id])
+            redirect(action:list)
+            return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.error.code == "default.not.found") {
+            redirect(action:list)
+            return
+        }
+
+        redirect(action:show, id: params.id)
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def siteInstance = Site.get( params.id )
+
+        if(!siteInstance) {
+            flash.message = "Site not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ siteInstance : siteInstance ]
+        }
+    }
+
+    def update = {
+        def siteInstance = Site.get( params.id )
+        if(siteInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(siteInstance.version > version) {
+                    
+                    siteInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[siteInstance:siteInstance])
+                    return
+                }
+            }
+            siteInstance.properties = params
+            if(!siteInstance.hasErrors() && siteInstance.save(flush: true)) {
+                flash.message = "Site ${params.id} updated"
+                redirect(action:show,id:siteInstance.id)
+            }
+            else {
+                render(view:'edit',model:[siteInstance:siteInstance])
+            }
+        }
+        else {
+            flash.message = "Site not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def siteInstance = new Site()
+        siteInstance.properties = params
+        return ['siteInstance':siteInstance]
+    }
+
+    def save = {
+        def siteInstance = new Site(params)
+        if(!siteInstance.hasErrors() && siteInstance.save(flush: true)) {
+            flash.message = "Site ${siteInstance.id} created"
+            redirect(action:show,id:siteInstance.id)
+        }
+        else {
+            render(view:'create',model:[siteInstance:siteInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/SiteExtendedAttributeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/SiteExtendedAttributeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/SiteExtendedAttributeDetailedController.groovy	(revision 875)
@@ -0,0 +1,100 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class SiteExtendedAttributeDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ siteExtendedAttributeInstanceList: SiteExtendedAttribute.list( params ), siteExtendedAttributeInstanceTotal: SiteExtendedAttribute.count() ]
+    }
+
+    def show = {
+        def siteExtendedAttributeInstance = SiteExtendedAttribute.get( params.id )
+
+        if(!siteExtendedAttributeInstance) {
+            flash.message = "SiteExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ siteExtendedAttributeInstance : siteExtendedAttributeInstance ] }
+    }
+
+    def delete = {
+        def siteExtendedAttributeInstance = SiteExtendedAttribute.get( params.id )
+        if(siteExtendedAttributeInstance) {
+            try {
+                siteExtendedAttributeInstance.delete(flush:true)
+                flash.message = "SiteExtendedAttribute ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "SiteExtendedAttribute ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "SiteExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def siteExtendedAttributeInstance = SiteExtendedAttribute.get( params.id )
+
+        if(!siteExtendedAttributeInstance) {
+            flash.message = "SiteExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ siteExtendedAttributeInstance : siteExtendedAttributeInstance ]
+        }
+    }
+
+    def update = {
+        def siteExtendedAttributeInstance = SiteExtendedAttribute.get( params.id )
+        if(siteExtendedAttributeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(siteExtendedAttributeInstance.version > version) {
+                    
+                    siteExtendedAttributeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[siteExtendedAttributeInstance:siteExtendedAttributeInstance])
+                    return
+                }
+            }
+            siteExtendedAttributeInstance.properties = params
+            if(!siteExtendedAttributeInstance.hasErrors() && siteExtendedAttributeInstance.save(flush: true)) {
+                flash.message = "SiteExtendedAttribute ${params.id} updated"
+                redirect(action:show,id:siteExtendedAttributeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[siteExtendedAttributeInstance:siteExtendedAttributeInstance])
+            }
+        }
+        else {
+            flash.message = "SiteExtendedAttribute not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def siteExtendedAttributeInstance = new SiteExtendedAttribute()
+        siteExtendedAttributeInstance.properties = params
+        return ['siteExtendedAttributeInstance':siteExtendedAttributeInstance]
+    }
+
+    def save = {
+        def siteExtendedAttributeInstance = new SiteExtendedAttribute(params)
+        if(!siteExtendedAttributeInstance.hasErrors() && siteExtendedAttributeInstance.save(flush: true)) {
+            flash.message = "SiteExtendedAttribute ${siteExtendedAttributeInstance.id} created"
+            redirect(action:show,id:siteExtendedAttributeInstance.id)
+        }
+        else {
+            render(view:'create',model:[siteExtendedAttributeInstance:siteExtendedAttributeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/SupplierDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/SupplierDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/SupplierDetailedController.groovy	(revision 875)
@@ -0,0 +1,110 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+class SupplierDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ supplierInstanceList: Supplier.list( params ), supplierInstanceTotal: Supplier.count() ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def supplierInstance = Supplier.get( params.id )
+
+        if(!supplierInstance) {
+            flash.message = "Supplier not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ supplierInstance : supplierInstance ] }
+    }
+
+    def delete = {
+        def supplierInstance = Supplier.get( params.id )
+        if(supplierInstance) {
+            try {
+                supplierInstance.delete(flush:true)
+                flash.message = "Supplier ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "Supplier ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "Supplier not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def supplierInstance = Supplier.get( params.id )
+
+        if(!supplierInstance) {
+            flash.message = "Supplier not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ supplierInstance : supplierInstance ]
+        }
+    }
+
+    def update = {
+        def supplierInstance = Supplier.get( params.id )
+        if(supplierInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(supplierInstance.version > version) {
+                    
+                    supplierInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[supplierInstance:supplierInstance])
+                    return
+                }
+            }
+            supplierInstance.properties = params
+            if(!supplierInstance.hasErrors() && supplierInstance.save(flush: true)) {
+                flash.message = "Supplier ${params.id} updated"
+                redirect(action:show,id:supplierInstance.id)
+            }
+            else {
+                render(view:'edit',model:[supplierInstance:supplierInstance])
+            }
+        }
+        else {
+            flash.message = "Supplier not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def supplierInstance = new Supplier()
+        supplierInstance.properties = params
+        return ['supplierInstance':supplierInstance]
+    }
+
+    def save = {
+        def supplierInstance = new Supplier(params)
+        if(!supplierInstance.hasErrors() && supplierInstance.save(flush: true)) {
+            flash.message = "Supplier ${supplierInstance.id} created"
+            redirect(action:show,id:supplierInstance.id)
+        }
+        else {
+            render(view:'create',model:[supplierInstance:supplierInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/SupplierTypeDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/SupplierTypeDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/SupplierTypeDetailedController.groovy	(revision 875)
@@ -0,0 +1,113 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager'])
+class SupplierTypeDetailedController extends BaseController {
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ supplierTypeInstanceList: SupplierType.list( params ), supplierTypeInstanceTotal: SupplierType.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_AssetManager', 'ROLE_AssetUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def supplierTypeInstance = SupplierType.get( params.id )
+
+        if(!supplierTypeInstance) {
+            flash.message = "SupplierType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ supplierTypeInstance : supplierTypeInstance ] }
+    }
+
+    def delete = {
+        def supplierTypeInstance = SupplierType.get( params.id )
+        if(supplierTypeInstance) {
+            try {
+                supplierTypeInstance.delete(flush:true)
+                flash.message = "SupplierType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "SupplierType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "SupplierType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def supplierTypeInstance = SupplierType.get( params.id )
+
+        if(!supplierTypeInstance) {
+            flash.message = "SupplierType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ supplierTypeInstance : supplierTypeInstance ]
+        }
+    }
+
+    def update = {
+        def supplierTypeInstance = SupplierType.get( params.id )
+        if(supplierTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(supplierTypeInstance.version > version) {
+                    
+                    supplierTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[supplierTypeInstance:supplierTypeInstance])
+                    return
+                }
+            }
+            supplierTypeInstance.properties = params
+            if(!supplierTypeInstance.hasErrors() && supplierTypeInstance.save(flush: true)) {
+                flash.message = "SupplierType ${params.id} updated"
+                redirect(action:show,id:supplierTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[supplierTypeInstance:supplierTypeInstance])
+            }
+        }
+        else {
+            flash.message = "SupplierType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def supplierTypeInstance = new SupplierType()
+        supplierTypeInstance.properties = params
+        return ['supplierTypeInstance':supplierTypeInstance]
+    }
+
+    def save = {
+        def supplierTypeInstance = new SupplierType(params)
+        if(!supplierTypeInstance.hasErrors() && supplierTypeInstance.save(flush: true)) {
+            flash.message = "SupplierType ${supplierTypeInstance.id} created"
+            redirect(action:show,id:supplierTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[supplierTypeInstance:supplierTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskBudgetStatusController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskBudgetStatusController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskBudgetStatusController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class TaskBudgetStatusController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ taskBudgetStatusInstanceList: TaskBudgetStatus.list( params ), taskBudgetStatusInstanceTotal: TaskBudgetStatus.count() ]
+    }
+
+    def show = {
+        def taskBudgetStatusInstance = TaskBudgetStatus.get( params.id )
+
+        if(!taskBudgetStatusInstance) {
+            flash.message = "TaskBudgetStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ taskBudgetStatusInstance : taskBudgetStatusInstance ] }
+    }
+
+    def delete = {
+        def taskBudgetStatusInstance = TaskBudgetStatus.get( params.id )
+        if(taskBudgetStatusInstance) {
+            try {
+                taskBudgetStatusInstance.delete(flush:true)
+                flash.message = "TaskBudgetStatus ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "TaskBudgetStatus ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "TaskBudgetStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def taskBudgetStatusInstance = TaskBudgetStatus.get( params.id )
+
+        if(!taskBudgetStatusInstance) {
+            flash.message = "TaskBudgetStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ taskBudgetStatusInstance : taskBudgetStatusInstance ]
+        }
+    }
+
+    def update = {
+        def taskBudgetStatusInstance = TaskBudgetStatus.get( params.id )
+        if(taskBudgetStatusInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(taskBudgetStatusInstance.version > version) {
+                    
+                    taskBudgetStatusInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[taskBudgetStatusInstance:taskBudgetStatusInstance])
+                    return
+                }
+            }
+            taskBudgetStatusInstance.properties = params
+            if(!taskBudgetStatusInstance.hasErrors() && taskBudgetStatusInstance.save(flush: true)) {
+                flash.message = "TaskBudgetStatus ${params.id} updated"
+                redirect(action:show,id:taskBudgetStatusInstance.id)
+            }
+            else {
+                render(view:'edit',model:[taskBudgetStatusInstance:taskBudgetStatusInstance])
+            }
+        }
+        else {
+            flash.message = "TaskBudgetStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def taskBudgetStatusInstance = new TaskBudgetStatus()
+        taskBudgetStatusInstance.properties = params
+        return ['taskBudgetStatusInstance':taskBudgetStatusInstance]
+    }
+
+    def save = {
+        def taskBudgetStatusInstance = new TaskBudgetStatus(params)
+        if(!taskBudgetStatusInstance.hasErrors() && taskBudgetStatusInstance.save(flush: true)) {
+            flash.message = "TaskBudgetStatus ${taskBudgetStatusInstance.id} created"
+            redirect(action:show,id:taskBudgetStatusInstance.id)
+        }
+        else {
+            render(view:'create',model:[taskBudgetStatusInstance:taskBudgetStatusInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskDetailedController.groovy	(revision 875)
@@ -0,0 +1,933 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import com.zeddware.grails.plugins.filterpane.FilterUtils
+import org.springframework.web.servlet.support.RequestContextUtils as RCU
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+class TaskDetailedController extends BaseController {
+
+    def authService
+    def taskService
+    def taskSearchService
+    def taskReportService
+    def filterService
+    def exportService
+    def dateUtilService
+
+    // these actions only accept POST requests
+    static allowedMethods = [save:'POST',update:'POST',restore:'POST', trash:'POST',
+                                                approve:'POST', renegeApproval:'POST', complete:'POST',
+                                                reopen:'POST', setAttentionFlag:'POST', clearAttentionFlag:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def index = { redirect(action: 'search', params: params) }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def setSearchParamsMax = {
+        def max = 1000
+        if(params.newMax?.isInteger()) {
+            def i = params.newMax.toInteger()
+            if(i > 0 && i <= max)
+                session.taskSearchParamsMax = params.newMax
+            if(i > max)
+                session.taskSearchParamsMax = max
+        }
+        forward(action: 'search', params: params)
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def setSearchCalendarParamsMax = {
+        def max = 1000
+        if(params.newMax?.isInteger()) {
+            def i = params.newMax.toInteger()
+            if(i > 0 && i <= max)
+                session.taskSearchCalendarParamsMax = params.newMax
+            if(i > max)
+                session.taskSearchCalendarParamsMax = max
+        }
+        forward(action: 'searchCalendar', params: params)
+    }
+
+    /**
+    * Search for tasks.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def search = {
+
+        if(session.taskSearchParamsMax)
+            params.max = session.taskSearchParamsMax
+
+        // Protect filterPane.
+        params.max = Math.min( params.max ? params.max.toInteger() : 100,  1000 )
+
+        // View main data.
+        def taskInstanceList = []
+        def taskInstanceTotal
+        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+        def isFilterApplied = FilterUtils.isFilterApplied(params)
+
+        // Restore search unless a new search is being requested.
+        if(!params.quickSearch && !filterParams) {
+            if(session.taskSearchFilterParams) {
+                session.taskSearchFilterParams.each() { params[it.key] = it.value }
+                params.filter = session.taskSearchFilter
+                isFilterApplied = FilterUtils.isFilterApplied(params)
+            }
+        }
+        if(!params.quickSearch) {
+            if(session.taskSearchQuickSearch) {
+                params.quickSearch = session.taskSearchQuickSearch
+                params.person = Person.get(session.taskQuickSearchPersonId.toLong())
+                params.startDate = session.taskQuickSearchStartDate
+                params.endDate = session.taskQuickSearchEndDate
+                params.includeCompleted = session.taskQuickSearchIncludeCompleted
+            }
+        }
+
+        // Remember sort if supplied, otherwise try to restore.
+        if(params.sort && params.order) {
+            // Reset to defaultSort if requested.
+            if(params.sort == 'defaultSort') {
+                params.sort = null
+                params.order = null
+                session.removeAttribute("taskSearchSort")
+                session.removeAttribute("taskSearchOrder")
+            }
+            else {
+                session.taskSearchSort = params.sort
+                session.taskSearchOrder = params.order
+            }
+        }
+        else if(session.taskSearchSort && session.taskSearchOrder) {
+            params.sort = session.taskSearchSort
+            params.order = session.taskSearchOrder
+        }
+
+        if(isFilterApplied) {
+            // filterPane:
+            params.sort = params.sort ?: "id"
+            params.order = params.order ?: "desc"
+            if(params.sort == "attentionFlag") // See ticket #64 in Trac.
+                params.sort = "id"
+            // Prevent tasks in the trash being returned unless explicitly requested.
+            if(!params.filter.op.trash) {
+                params.filter.op.trash = "Equal"
+                params.filter.trash = "false"
+            }
+            // Call filterService.
+            taskInstanceList = filterService.filter( params, Task )
+            taskInstanceTotal = filterService.count( params, Task )
+            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+            // Remember search.
+            session.taskSearchFilterParams = new LinkedHashMap(filterParams)
+            session.taskSearchFilter = new LinkedHashMap(params.filter)
+        }
+        else {
+            // Quick Search:
+            def result = taskSearchService.getQuickSearch(params, RCU.getLocale(request))
+            taskInstanceList = result.taskInstanceList
+            taskInstanceTotal = result.taskInstanceList.totalCount
+            params.message = result.message
+            params.quickSearch = result.quickSearch
+            params.person = result.person
+            params.startDate = result.startDate
+            params.endDate = result.endDate
+            params.includeCompleted = result.includeCompleted
+            // Remember search.
+            session.removeAttribute("taskSearchFilterParams")
+            session.removeAttribute("taskSearchFilter")
+            session.taskSearchQuickSearch = result.quickSearch
+            session.taskQuickSearchPersonId = result.person.id
+            session.taskQuickSearchStartDate = result.startDate
+            session.taskQuickSearchEndDate = result.endDate
+            session.taskQuickSearchIncludeCompleted = result.includeCompleted
+        }
+
+        // export plugin:
+        if(params?.format && params.format != "html") {
+
+            def dateFmt = { date ->
+                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
+            }
+
+            String title
+            if(params.quickSearch)
+                title = params.message
+            else
+                title = "Filtered tasks."
+
+            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
+            response.setHeader("Content-disposition", "attachment; filename=Tasks.${params.extension}")
+            List fields = ["id", "targetStartDate", "primaryAsset", "description", "taskPriority", "taskType", "taskStatus"]
+            Map labels = ["id": "Task #", "targetStartDate": "Target Start Date", "primaryAsset": "Asset",
+                                    "description": "Description", "taskPriority": "Task Priority",
+                                    "taskType": "Task Type", "taskStatus": "Task Status"]
+            Map formatters = [ targetStartDate: dateFmt]
+            Map parameters = [title: title, separator: ","]
+
+            exportService.export(params.format, response.outputStream, taskInstanceList, fields, labels, formatters, parameters)
+        }
+
+        // Add some basic params to filterParams.
+        filterParams.max = params.max
+        filterParams.offset = params.offset?.toInteger() ?: 0
+        filterParams.sort = params.sort ?: "id"
+        filterParams.order = params.order ?: "desc"
+
+        // Get some associatedProperty values for filterpane.
+        def associatedPropertyValues = [:]
+        def associatedPropertyMax = 10000
+        def taskPriorityNameQuery = 'select distinct tp.name from TaskPriority tp where tp.isActive = ? order by tp.name'
+        associatedPropertyValues.taskPriorityList = TaskPriority.executeQuery(taskPriorityNameQuery, [true], [max:associatedPropertyMax])
+        def lastNameQuery = 'select distinct p.lastName from Person p where p.isActive = ? order by p.lastName'
+        associatedPropertyValues.lastNameList = Person.executeQuery(lastNameQuery, [true], [max:associatedPropertyMax])
+        def firstNameQuery = 'select distinct p.firstName from Person p where p.isActive = ? order by p.firstName'
+        associatedPropertyValues.firstNameList = Person.executeQuery(firstNameQuery, [true], [max:associatedPropertyMax])
+        def taskGroupNameQuery = 'select distinct tg.name from TaskGroup tg where tg.isActive = ? order by tg.name'
+        associatedPropertyValues.taskGroupList = TaskGroup.executeQuery(taskGroupNameQuery, [true], [max:associatedPropertyMax])
+        def assetNameQuery = 'select distinct a.name from Asset a where a.isActive = ? order by a.name'
+        associatedPropertyValues.assetList = Asset.executeQuery(assetNameQuery, [true], [max:associatedPropertyMax])
+        def highestSeverityCodeQuery = 'select distinct cs.code from ConditionSeverity cs where cs.isActive = ? order by cs.code'
+        associatedPropertyValues.highestSeverityList = ConditionSeverity.executeQuery(highestSeverityCodeQuery, [true], [max:associatedPropertyMax])
+        def taskStatusNameQuery = 'select a.name from TaskStatus a where a.isActive = ? order by a.id'
+        associatedPropertyValues.taskStatusList = TaskStatus.executeQuery(taskStatusNameQuery, [true], [max:associatedPropertyMax])
+        def taskTypeNameQuery = 'select a.name from TaskType a where a.isActive = ? order by a.name'
+        associatedPropertyValues.taskTypeList = TaskType.executeQuery(taskTypeNameQuery, [true], [max:associatedPropertyMax])
+        def startOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), -10))
+        def endOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), 10))
+        associatedPropertyValues.yearRange = startOfYearRange..endOfYearRange
+
+        return[ taskInstanceList: taskInstanceList,
+                        taskInstanceTotal: taskInstanceTotal,
+                        filterParams: filterParams,
+                        params: params,
+                        associatedPropertyValues: associatedPropertyValues,
+                        quickSearchSelection: taskSearchService.quickSearchSelection]
+
+    } // search
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def searchCalendar = {
+
+        // No pagination for calendar.
+        params.offset = 0
+
+        // Restore params.max
+        if(session.taskSearchCalendarParamsMax)
+            params.max = session.taskSearchCalendarParamsMax
+
+        // Protect filterPane.
+        params.max = Math.min( params.max ? params.max.toInteger() : 100,  1000 )
+
+        def displayList = []
+        def taskInstanceList = []
+        def taskInstanceTotal
+        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+        def isFilterApplied = FilterUtils.isFilterApplied(params)
+
+        // Restore search unless a new search is being requested.
+        if(!params.quickSearch && !filterParams) {
+            if(session.taskSearchCalendarFilterParams) {
+                session.taskSearchCalendarFilterParams.each() { params[it.key] = it.value }
+                params.filter = session.taskSearchCalendarFilter
+                isFilterApplied = FilterUtils.isFilterApplied(params)
+            }
+        }
+        if(!params.quickSearch) {
+            if(session.taskSearchCalendarQuickSearch) {
+                params.quickSearch = session.taskSearchCalendarQuickSearch
+                params.person = Person.get(session.taskCalendarQuickSearchPersonId.toLong())
+                params.startDate = session.taskCalendarQuickSearchStartDate
+                params.endDate = session.taskCalendarQuickSearchEndDate
+                params.includeCompleted = session.taskCalendarQuickSearchIncludeCompleted
+            }
+        }
+
+        // The date the calendar will use to determine the month to show.
+        // Use session, if not specified in params, otherwise use today.
+        def showDate = new Date()
+        if(params.showMonth) {
+            if(params.showYear)
+                showDate = dateUtilService.makeDate(params.showYear, params.showMonth)
+            else
+                showDate = dateUtilService.makeDate(dateUtilService.getYearFromDate(showDate), params.showMonth)
+            // Remember the showDate.
+            session.taskSearchCalendarShowDate = showDate
+        }
+        else if(session.taskSearchCalendarShowDate)
+            showDate = session.taskSearchCalendarShowDate
+
+        // Get the dates for the calendar month controls.
+        def calendarMonthControls = getCalendarMonthControls(showDate)
+
+        if(isFilterApplied) {
+            // filterPane:
+            params.sort = params.sort ?: "id"
+            params.order = params.order ?: "desc"
+            if(params.sort == "attentionFlag") // See ticket #64 in Trac.
+                params.sort = "id"
+            // Prevent tasks in the trash being returned unless explicitly requested.
+            if(!params.filter.op.trash) {
+                params.filter.op.trash = "Equal"
+                params.filter.trash = "false"
+            }
+            // Call filterService.
+            taskInstanceList = filterService.filter( params, Task )
+            taskInstanceTotal = filterService.count( params, Task )
+            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
+            // Remember search.
+            session.taskSearchCalendarFilterParams = new LinkedHashMap(filterParams)
+            session.taskSearchCalendarFilter = new LinkedHashMap(params.filter)
+        }
+        else {
+            // Quick Search:
+            def result = taskSearchService.getQuickSearch(params, RCU.getLocale(request))
+            taskInstanceList = result.taskInstanceList
+            taskInstanceTotal = result.taskInstanceList.totalCount
+            params.message = result.message
+            params.quickSearch = result.quickSearch
+            params.person = result.person
+            params.startDate = result.startDate
+            params.endDate = result.endDate
+            params.includeCompleted = result.includeCompleted
+            // Remember search.
+            session.removeAttribute("taskSearchCalendarFilterParams")
+            session.removeAttribute("taskSearchCalendarFilter")
+            session.taskSearchCalendarQuickSearch = result.quickSearch
+            session.taskCalendarQuickSearchPersonId = result.person.id
+            session.taskCalendarQuickSearchStartDate = result.startDate
+            session.taskCalendarQuickSearchEndDate = result.endDate
+            session.taskCalendarQuickSearchIncludeCompleted = result.includeCompleted
+        }
+
+//         displayList = taskReportService.getWorkLoadSummary(
+//                                     [taskInstanceList: taskInstanceList], RCU.getLocale(request)
+//                                 ).displayList
+
+        // export plugin:
+        if(params?.format && params.format != "html") {
+
+            def dateFmt = { date ->
+                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
+            }
+
+            String title
+            if(params.quickSearch)
+                title = params.message
+            else
+                title = "Filtered tasks."
+
+            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
+            response.setHeader("Content-disposition", "attachment; filename=Tasks.${params.extension}")
+            List fields = ["id", "targetStartDate", "primaryAsset", "description", "taskPriority", "taskType", "taskStatus"]
+            Map labels = ["id": "Task #", "targetStartDate": "Target Start Date", "primaryAsset": "Asset",
+                                    "description": "Description", "taskPriority": "Task Priority",
+                                    "taskType": "Task Type", "taskStatus": "Task Status"]
+            Map formatters = [ targetStartDate: dateFmt]
+            Map parameters = [title: title, separator: ","]
+
+            exportService.export(params.format, response.outputStream, taskInstanceList, fields, labels, formatters, parameters)
+        }
+
+        if(taskInstanceTotal > params.max)
+            params.errorMessage = g.message(code:"task.search.calendar.text.too.many.results", args:[params.max])
+
+        // Add some basic params to filterParams.
+        filterParams.max = params.max
+        filterParams.offset = params.offset?.toInteger() ?: 0
+        filterParams.sort = params.sort ?: "id"
+        filterParams.order = params.order ?: "desc"
+
+        // Get some associatedProperty values for filterpane.
+        def associatedPropertyValues = [:]
+        def associatedPropertyMax = 10000
+        def taskPriorityNameQuery = 'select distinct tp.name from TaskPriority tp where tp.isActive = ? order by tp.name'
+        associatedPropertyValues.taskPriorityList = TaskPriority.executeQuery(taskPriorityNameQuery, [true], [max:associatedPropertyMax])
+        def lastNameQuery = 'select distinct p.lastName from Person p where p.isActive = ? order by p.lastName'
+        associatedPropertyValues.lastNameList = Person.executeQuery(lastNameQuery, [true], [max:associatedPropertyMax])
+        def firstNameQuery = 'select distinct p.firstName from Person p where p.isActive = ? order by p.firstName'
+        associatedPropertyValues.firstNameList = Person.executeQuery(firstNameQuery, [true], [max:associatedPropertyMax])
+        def taskGroupNameQuery = 'select distinct tg.name from TaskGroup tg where tg.isActive = ? order by tg.name'
+        associatedPropertyValues.taskGroupList = TaskGroup.executeQuery(taskGroupNameQuery, [true], [max:associatedPropertyMax])
+        def assetNameQuery = 'select distinct a.name from Asset a where a.isActive = ? order by a.name'
+        associatedPropertyValues.assetList = Asset.executeQuery(assetNameQuery, [true], [max:associatedPropertyMax])
+        def highestSeverityCodeQuery = 'select distinct cs.code from ConditionSeverity cs where cs.isActive = ? order by cs.code'
+        associatedPropertyValues.highestSeverityList = ConditionSeverity.executeQuery(highestSeverityCodeQuery, [true], [max:associatedPropertyMax])
+        def taskStatusNameQuery = 'select a.name from TaskStatus a where a.isActive = ? order by a.id'
+        associatedPropertyValues.taskStatusList = TaskStatus.executeQuery(taskStatusNameQuery, [true], [max:associatedPropertyMax])
+        def taskTypeNameQuery = 'select a.name from TaskType a where a.isActive = ? order by a.name'
+        associatedPropertyValues.taskTypeList = TaskType.executeQuery(taskTypeNameQuery, [true], [max:associatedPropertyMax])
+        def startOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), -10))
+        def endOfYearRange = dateUtilService.getYearFromDate(dateUtilService.plusYear(new Date(), 10))
+        associatedPropertyValues.yearRange = startOfYearRange..endOfYearRange
+
+        return[taskInstanceList: taskInstanceList,
+                        taskInstanceTotal: taskInstanceTotal,
+                        filterParams: filterParams,
+                        params: params,
+                        associatedPropertyValues: associatedPropertyValues,
+                        showDate: showDate,
+                        today: calendarMonthControls.today,
+                        previousMonth: calendarMonthControls.previousMonth,
+                        nextMonth: calendarMonthControls.nextMonth,
+                        previousYear: calendarMonthControls.previousYear,
+                        nextYear: calendarMonthControls.nextYear,
+                        quickSearchSelection: taskSearchService.quickSearchSelection]
+
+    } // searchCalendar
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        // Used by navigation.
+        if(params.id == 'nav') {
+            params.id = session.currentTaskId ?: null
+            redirect(action: show, id: params.id)
+            return
+        }
+
+        def showTab = [:]
+        switch (params.showTab) {
+            case "showProcedureTab":
+                showTab.procedure =  new String("true")
+                break
+            case "showRecurrenceTab":
+                showTab.recurrence =  new String("true")
+                break
+            case "showInventoryTab":
+                showTab.inventory = new String("true")
+                break
+            case "showSubTasksTab":
+                showTab.subTasks = new String("true")
+                break
+            default:
+                showTab.task = new String("true")
+        }
+
+        def taskInstance = Task.get( params.id )
+
+        if(!taskInstance) {
+            flash.message = "Task not found with id ${params.id}"
+            redirect(action: 'search')
+        }
+        else {
+            // Remember the current task id for use with navigation.
+            session.currentTaskId = params.id
+
+            params.max = 10
+            params.order = "desc"
+            params.sort = "id"
+
+            def entryFaultList = Entry.withCriteria {
+                                                                eq("entryType", EntryType.get(1))
+                                                                eq("task", taskInstance)
+                                                        }
+
+            def entryCauseList = Entry.withCriteria {
+                                                                eq("entryType", EntryType.get(2))
+                                                                eq("task", taskInstance)
+                                                        }
+
+            def entryWorkDoneList = Entry.withCriteria {
+                                                                eq("entryType", EntryType.get(3))
+                                                                eq("task", taskInstance)
+                                                        }
+
+            def entryPMList = Entry.withCriteria {
+                                                                eq("entryType", EntryType.get(6))
+                                                                eq("task", taskInstance)
+                                                        }
+
+            def subTaskInstanceList = Task.findAllByParentTaskAndTrash(taskInstance, false, params)
+            def subTaskInstanceTotal = Task.countByParentTaskAndTrash(taskInstance, false)
+
+            def inventoryMovementList = InventoryMovement.findAllByTask(taskInstance, [max:100, sort:"id", order:"desc", offset:0])
+
+            def taskModificationList = TaskModification.findAllByTask(taskInstance, [max:100, sort:"id", order:"asc", offset:0])
+
+            def assignedGroupList = taskInstance.assignedGroups.sort { p1, p2 -> p1.personGroup.name.compareToIgnoreCase(p2.personGroup.name) }
+            def assignedPersonList = taskInstance.assignedPersons.sort { p1, p2 -> p1.person.firstName.compareToIgnoreCase(p2.person.firstName) }
+
+            def taskProcedureRevision = TaskProcedureRevision.get(taskInstance.taskProcedureRevision?.id)
+            def taskProcedureExits = new Boolean("true")
+            if(!taskProcedureRevision) {
+                taskProcedureExits = false
+            }
+
+            def taskRecurringScheduleInstance = TaskRecurringSchedule.get(taskInstance.taskRecurringSchedule?.id)
+            def taskRecurringScheduleExits= new Boolean("true")
+            if(!taskRecurringScheduleInstance) {
+                taskRecurringScheduleExits = false
+            }
+
+            return [ taskInstance: taskInstance,
+                            entryFaultList: entryFaultList,
+                            entryCauseList: entryCauseList,
+                            entryWorkDoneList: entryWorkDoneList,
+                            entryPMList: entryPMList,
+                            taskProcedureRevision: taskProcedureRevision,
+                            taskProcedureExits: taskProcedureExits,
+                            showTab: showTab,
+                            subTaskInstanceList: subTaskInstanceList,
+                            subTaskInstanceTotal: subTaskInstanceTotal,
+                            subTaskInstanceMax: params.max,
+                            taskRecurringScheduleInstance: taskRecurringScheduleInstance,
+                            taskRecurringScheduleExits: taskRecurringScheduleExits,
+                            inventoryMovementList: inventoryMovementList,
+                            taskModificationList: taskModificationList,
+                            assignedGroupList: assignedGroupList,
+                            assignedPersonList: assignedPersonList]
+        }
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def restore = {
+
+        def result = taskService.restore(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} has been restored."
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def trash = {
+
+        def result = taskService.trash(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} has been moved to trash."
+                redirect(action: 'search')
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+    def approve = {
+
+        def result = taskService.approve(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} has been approved."
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+    def renegeApproval = {
+
+        def result = taskService.renegeApproval(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} has had approval removed."
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def complete = {
+
+        def result = taskService.complete(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} has been completed."
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def setAttentionFlag = {
+
+        def result = taskService.setAttentionFlag(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} has been flagged for attention."
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def clearAttentionFlag = {
+
+        def result = taskService.clearAttentionFlag(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} attention flag cleared."
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def reopen = {
+
+        def result = taskService.reopen(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} has been reopened."
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        if(result.taskInstance)
+            redirect(action: show, id: params.id)
+        else
+            redirect(action: 'search')
+
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        // Used by navigation.
+        if(params.id == 'nav') {
+            params.id = session.currentTaskId ?: null
+            redirect(action: edit, id: params.id)
+            return
+        }
+
+        def taskInstance = Task.get( params.id )
+
+        if(!taskInstance) {
+            flash.message = "Task not found with id ${params.id}"
+            redirect(action: 'search')
+        }
+        else {
+            // Remember the current task id for use with navigation.
+            session.currentTaskId = params.id
+
+            if(taskInstance.trash) {
+                flash.message = "You may not edit tasks that are in the trash."
+                redirect(action: 'show', id: taskInstance.id)
+                return
+            }
+//             def possibleParentList = taskService.possibleParentList(taskInstance)
+//             return [ taskInstance : taskInstance, possibleParentList: possibleParentList ]
+            return [ taskInstance : taskInstance ]
+        }
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def update = {
+
+        def result = taskService.update(params)
+
+        if(!result.error) {
+                flash.message = "Task ${params.id} updated"
+                redirect(action: show, id: params.id)
+                return
+        }
+
+        if(result.error.code == "task.modifications.failedToSave")
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        render(view:'edit',model:[taskInstance:result.taskInstance.attach()])
+
+    }
+
+    /**
+    * The create action is used to create scheduled types of tasks.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+    def create = {
+        def taskInstance = new Task()
+
+        // Set the targetStartDate if specified, used by searchCalendar view.
+        if(params.year && params.month && params.day) {
+            def date = dateUtilService.makeDate(params.year, params.month, params.day)
+            taskInstance.targetStartDate = date
+            taskInstance.targetCompletionDate = date
+        }
+
+        // Default leadPerson to current user, unless supplied in params.
+        taskInstance.leadPerson = authService.currentUser
+
+        // Apply params, overiding anything above.
+        taskInstance.properties = params
+
+        def scheduledTaskTypes = taskService.scheduledTaskTypes
+        def scheduledTaskPriorities = taskService.scheduledTaskPriorities
+        taskInstance.taskPriority = scheduledTaskPriorities.default
+        return ['taskInstance': taskInstance,
+                    'scheduledTaskTypes': scheduledTaskTypes,
+                    'scheduledTaskPriorities': scheduledTaskPriorities.list]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def save = {
+        def result = taskService.save(params)
+
+        if(!result.error) {
+            flash.message = "Task ${result.taskInstance.id} created."
+            redirect(action: 'show', id: result.taskInstance.id)
+            return
+        }
+
+        if(result.error.code == "task.modifications.failedToSave")
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+
+        def scheduledTaskTypes = taskService.scheduledTaskTypes
+        def scheduledTaskPriorities = taskService.scheduledTaskPriorities
+        render(view:'create', model:[taskInstance:result.taskInstance,
+                                                    'scheduledTaskTypes': scheduledTaskTypes,
+                                                    'scheduledTaskPriorities': scheduledTaskPriorities.list])
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def listSubTasks = {
+        def parentTaskInstance = Task.get(params.id)
+
+        if(!parentTaskInstance) {
+            flash.message = "Task not found with id ${params.id}"
+            redirect(action: 'search')
+        }
+        else {
+        params.max = Math.min( params.max ? params.max.toInteger() : 200,  200)
+        def filterParams = [:]
+        def subTaskInstanceList = Task.findAllByParentTaskAndTrash(parentTaskInstance, false, params)
+        def subTaskInstanceTotal = Task.countByParentTaskAndTrash(parentTaskInstance, false)
+
+        [ taskInstanceList: subTaskInstanceList,
+            taskInstanceTotal:  subTaskInstanceTotal,
+            parentTaskInstance: parentTaskInstance,
+            filterParams: filterParams]
+        }
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def createSubTask = {
+        def parentTaskInstance = Task.get(params.id)
+
+        if(parentTaskInstance) {
+
+            def result = taskService.createSubTask(parentTaskInstance)
+            if(!result.error) {
+                flash.message = "Sub Task ${result.taskInstance.id} created, please edit and update to your requirements."
+                redirect(action: 'edit', id: result.taskInstance.id)
+            }
+            else {
+                if(result.taskInstance.errors.hasFieldErrors("parentTask")) {
+                    flash.errorMessage = g.message(code:"task.operationNotPermittedOnTaskInTrash")
+                    redirect(action: 'show', id:  parentTaskInstance.id)
+                }
+                else {
+                    render(view: 'create', model:[taskInstance: result.taskInstance])
+                }
+            }
+        }
+
+        else {
+            flash.message = "Task not found with id ${params.id}"
+            redirect(action: 'search')
+        }
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def createUnscheduled = {
+        def taskInstance = new Task()
+
+        // Default leadPerson to current user, unless supplied in params.
+        taskInstance.leadPerson = authService.currentUser
+        taskInstance.properties = params
+
+        // Always for Unscheduled task.
+        taskInstance.taskType = TaskType.get(2) // Unscheduled Breakin.
+        def unscheduledTaskPriorities = taskService.unscheduledTaskPriorities
+        taskInstance.taskPriority = unscheduledTaskPriorities.default
+
+        return ['taskInstance': taskInstance, 'unscheduledTaskPriorities': unscheduledTaskPriorities.list]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def saveUnscheduled = {
+        def result = taskService.saveUnscheduled(params)
+
+        if(!result.error) {
+            flash.message = "Task ${result.taskInstance.id} created."
+            redirect(action: 'show', id: result.taskInstance.id)
+            return
+        }
+
+        if(result.error.code == "task.modifications.failedToSave")
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        def unscheduledTaskPriorities = taskService.unscheduledTaskPriorities
+
+        render(view:'createUnscheduled',
+                    model: ['taskInstance': result.taskInstance, 'unscheduledTaskPriorities': unscheduledTaskPriorities.list])
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def createImmediateCallout = {
+        def taskInstance = new Task()
+
+        def entryFaultInstance = new Entry(entryType: EntryType.get(1))  // Fault.
+        def entryCauseInstance = new Entry(entryType: EntryType.get(2))  // Cause.
+        def entryWorkDoneInstance = new Entry(entryType: EntryType.get(3))  // Work Done.
+
+        return ['taskInstance': taskInstance,
+                        'entryFaultInstance': entryFaultInstance,
+                        'entryCauseInstance': entryCauseInstance,
+                        'entryWorkDoneInstance': entryWorkDoneInstance]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def saveImmediateCallout = {
+        def result = taskService.saveImmediateCallout(params)
+
+        if(!result.error) {
+            flash.message = "Task ${result.taskInstance.id} created."
+            redirect(action: 'show', id: result.taskInstance.id)
+            return
+        }
+
+        if(result.error.code == "task.modifications.failedToSave")
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        render(view:'createImmediateCallout',
+                    model: ['taskInstance': result.taskInstance,
+                                'entryFaultInstance': result.entryFaultInstance,
+                                'entryCauseInstance': result.entryCauseInstance,
+                                'entryWorkDoneInstance': result.entryWorkDoneInstance])
+
+    }
+
+    /**
+    * Render a users total work done hours.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def workDone = {
+        def result = taskSearchService.getWorkDone(params, RCU.getLocale(request))
+
+        params.message = result.message
+
+        return[entries: result.entries,
+                    totalEntries : result.totalEntries,
+                    startOfDay: result.startOfDay,
+                    person: result.person,
+                    totalHours: result.totalHours,
+                    totalMinutes: result.totalMinutes]
+    } // workDone
+
+    /**
+    * Render work load hours.
+    */
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def workLoad= {
+        def result = taskSearchService.getWorkLoad(params, RCU.getLocale(request))
+
+        params.message = result.message
+        params.errorMessage = result.errorMessage
+
+        return[tasks: result.tasks,
+                    startDate: result.startDate,
+                    endDate: result.endDate,
+                    taskGroups: result.taskGroups,
+                    taskStatusList: result.taskStatusList,
+                    workLoadGroups: result.workLoadGroups,
+                    totalHours: result.totalHours,
+                    totalMinutes: result.totalMinutes]
+    } // workLoad
+
+    /**
+    * Get some integers for use by the month control links.
+    */
+    private getCalendarMonthControls(Date showDate) {
+        def result = [:]
+        result.today = [:]
+        result.today.date = new Date()
+        result.today.month = dateUtilService.getMonthFromDate(result.today.date)
+        result.today.year = dateUtilService.getYearFromDate(result.today.date)
+        result.nextMonth = [:]
+        result.nextMonth.date = dateUtilService.plusMonth(showDate)
+        result.nextMonth.month = dateUtilService.getMonthFromDate(result.nextMonth.date)
+        result.nextMonth.year = dateUtilService.getYearFromDate(result.nextMonth.date)
+        result.previousMonth =  [:]
+        result.previousMonth.date = dateUtilService.plusMonth(showDate, -1)
+        result.previousMonth.month = dateUtilService.getMonthFromDate(result.previousMonth.date)
+        result.previousMonth.year = dateUtilService.getYearFromDate(result.previousMonth.date)
+        result.nextYear = [:]
+        result.nextYear.date = dateUtilService.plusYear(showDate)
+        result.nextYear.month = dateUtilService.getMonthFromDate(result.nextYear.date)
+        result.nextYear.year = dateUtilService.getYearFromDate(result.nextYear.date)
+        result.previousYear = [:]
+        result.previousYear.date = dateUtilService.plusYear(showDate, -1)
+        result.previousYear.month = dateUtilService.getMonthFromDate(result.previousYear.date)
+        result.previousYear.year = dateUtilService.getYearFromDate(result.previousYear.date)
+        return result
+    }
+
+} // end of class.
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskGroupDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskGroupDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskGroupDetailedController.groovy	(revision 875)
@@ -0,0 +1,110 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+class TaskGroupDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ taskGroupInstanceList: TaskGroup.list( params ), taskGroupInstanceTotal: TaskGroup.count() ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def taskGroupInstance = TaskGroup.get( params.id )
+
+        if(!taskGroupInstance) {
+            flash.message = "TaskGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ taskGroupInstance : taskGroupInstance ] }
+    }
+
+    def delete = {
+        def taskGroupInstance = TaskGroup.get( params.id )
+        if(taskGroupInstance) {
+            try {
+                taskGroupInstance.delete(flush:true)
+                flash.message = "TaskGroup ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "TaskGroup ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "TaskGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def taskGroupInstance = TaskGroup.get( params.id )
+
+        if(!taskGroupInstance) {
+            flash.message = "TaskGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ taskGroupInstance : taskGroupInstance ]
+        }
+    }
+
+    def update = {
+        def taskGroupInstance = TaskGroup.get( params.id )
+        if(taskGroupInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(taskGroupInstance.version > version) {
+                    
+                    taskGroupInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[taskGroupInstance:taskGroupInstance])
+                    return
+                }
+            }
+            taskGroupInstance.properties = params
+            if(!taskGroupInstance.hasErrors() && taskGroupInstance.save(flush: true)) {
+                flash.message = "TaskGroup ${params.id} updated"
+                redirect(action:show,id:taskGroupInstance.id)
+            }
+            else {
+                render(view:'edit',model:[taskGroupInstance:taskGroupInstance])
+            }
+        }
+        else {
+            flash.message = "TaskGroup not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def taskGroupInstance = new TaskGroup()
+        taskGroupInstance.properties = params
+        return ['taskGroupInstance':taskGroupInstance]
+    }
+
+    def save = {
+        def taskGroupInstance = new TaskGroup(params)
+        if(!taskGroupInstance.hasErrors() && taskGroupInstance.save(flush: true)) {
+            flash.message = "TaskGroup ${taskGroupInstance.id} created"
+            redirect(action:show,id:taskGroupInstance.id)
+        }
+        else {
+            render(view:'create',model:[taskGroupInstance:taskGroupInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskModificationTypeController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskModificationTypeController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskModificationTypeController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class TaskModificationTypeController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ taskModificationTypeInstanceList: TaskModificationType.list( params ), taskModificationTypeInstanceTotal: TaskModificationType.count() ]
+    }
+
+    def show = {
+        def taskModificationTypeInstance = TaskModificationType.get( params.id )
+
+        if(!taskModificationTypeInstance) {
+            flash.message = "TaskModificationType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ taskModificationTypeInstance : taskModificationTypeInstance ] }
+    }
+
+    def delete = {
+        def taskModificationTypeInstance = TaskModificationType.get( params.id )
+        if(taskModificationTypeInstance) {
+            try {
+                taskModificationTypeInstance.delete(flush:true)
+                flash.message = "TaskModificationType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "TaskModificationType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "TaskModificationType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def taskModificationTypeInstance = TaskModificationType.get( params.id )
+
+        if(!taskModificationTypeInstance) {
+            flash.message = "TaskModificationType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ taskModificationTypeInstance : taskModificationTypeInstance ]
+        }
+    }
+
+    def update = {
+        def taskModificationTypeInstance = TaskModificationType.get( params.id )
+        if(taskModificationTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(taskModificationTypeInstance.version > version) {
+                    
+                    taskModificationTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[taskModificationTypeInstance:taskModificationTypeInstance])
+                    return
+                }
+            }
+            taskModificationTypeInstance.properties = params
+            if(!taskModificationTypeInstance.hasErrors() && taskModificationTypeInstance.save(flush: true)) {
+                flash.message = "TaskModificationType ${params.id} updated"
+                redirect(action:show,id:taskModificationTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[taskModificationTypeInstance:taskModificationTypeInstance])
+            }
+        }
+        else {
+            flash.message = "TaskModificationType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def taskModificationTypeInstance = new TaskModificationType()
+        taskModificationTypeInstance.properties = params
+        return ['taskModificationTypeInstance':taskModificationTypeInstance]
+    }
+
+    def save = {
+        def taskModificationTypeInstance = new TaskModificationType(params)
+        if(!taskModificationTypeInstance.hasErrors() && taskModificationTypeInstance.save(flush: true)) {
+            flash.message = "TaskModificationType ${taskModificationTypeInstance.id} created"
+            redirect(action:show,id:taskModificationTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[taskModificationTypeInstance:taskModificationTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskPriorityController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskPriorityController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskPriorityController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class TaskPriorityController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ taskPriorityInstanceList: TaskPriority.list( params ), taskPriorityInstanceTotal: TaskPriority.count() ]
+    }
+
+    def show = {
+        def taskPriorityInstance = TaskPriority.get( params.id )
+
+        if(!taskPriorityInstance) {
+            flash.message = "TaskPriority not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ taskPriorityInstance : taskPriorityInstance ] }
+    }
+
+    def delete = {
+        def taskPriorityInstance = TaskPriority.get( params.id )
+        if(taskPriorityInstance) {
+            try {
+                taskPriorityInstance.delete(flush:true)
+                flash.message = "TaskPriority ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "TaskPriority ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "TaskPriority not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def taskPriorityInstance = TaskPriority.get( params.id )
+
+        if(!taskPriorityInstance) {
+            flash.message = "TaskPriority not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ taskPriorityInstance : taskPriorityInstance ]
+        }
+    }
+
+    def update = {
+        def taskPriorityInstance = TaskPriority.get( params.id )
+        if(taskPriorityInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(taskPriorityInstance.version > version) {
+                    
+                    taskPriorityInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[taskPriorityInstance:taskPriorityInstance])
+                    return
+                }
+            }
+            taskPriorityInstance.properties = params
+            if(!taskPriorityInstance.hasErrors() && taskPriorityInstance.save(flush: true)) {
+                flash.message = "TaskPriority ${params.id} updated"
+                redirect(action:show,id:taskPriorityInstance.id)
+            }
+            else {
+                render(view:'edit',model:[taskPriorityInstance:taskPriorityInstance])
+            }
+        }
+        else {
+            flash.message = "TaskPriority not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def taskPriorityInstance = new TaskPriority()
+        taskPriorityInstance.properties = params
+        return ['taskPriorityInstance':taskPriorityInstance]
+    }
+
+    def save = {
+        def taskPriorityInstance = new TaskPriority(params)
+        if(!taskPriorityInstance.hasErrors() && taskPriorityInstance.save(flush: true)) {
+            flash.message = "TaskPriority ${taskPriorityInstance.id} created"
+            redirect(action:show,id:taskPriorityInstance.id)
+        }
+        else {
+            render(view:'create',model:[taskPriorityInstance:taskPriorityInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskProcedureDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskProcedureDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskProcedureDetailedController.groovy	(revision 875)
@@ -0,0 +1,179 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+class TaskProcedureDetailedController extends BaseController {
+
+    def filterService
+    def assetService
+    def taskProcedureService
+
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+
+        if(!params.filter)
+        { return [taskProcedureInstanceList: TaskProcedure.list(params), taskProcedureInstanceTotal: TaskProcedure.count()] }
+
+        // filterPane:
+        return[ taskProcedureInstanceList: filterService.filter( params, TaskProcedure ),
+            taskProcedureInstanceTotal: filterService.count( params, TaskProcedure ),
+            filterParams: com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params),
+            params:params ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def search = {
+        redirect(action:list)
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def taskProcedureInstance = TaskProcedure.get( params.id )
+
+        if(!taskProcedureInstance) {
+            flash.errorMessage = "TaskProcedure not found with id ${params.id}"
+            redirect(action:'list')
+            return
+        }
+
+        def taskProcedureRevision
+        if(params.revision?.toInteger())
+             taskProcedureRevision = taskProcedureInstance.getRevision( params.revision )
+        else
+             taskProcedureRevision = taskProcedureInstance.latestRevision
+
+        if(!taskProcedureRevision) {
+            flash.errorMessage = "TaskProcedure ${params.id} revision ${params.revision} not found"
+            redirect(action:'list')
+            return
+        }
+
+        return [taskProcedureRevision: taskProcedureRevision]
+
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        //if(params._action_Edit)
+            params.action='edit'
+
+        def taskProcedureInstance = TaskProcedure.get( params.id )
+
+        if(!taskProcedureInstance) {
+            flash.errorMessage = "TaskProcedure not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            def assemblies = assetService.getAssemblies(taskProcedureInstance.linkedTask.primaryAsset)
+            return [ taskProcedureInstance : taskProcedureInstance,
+                            assemblies: assemblies ]
+        }
+    }
+
+    def update = {
+        def result = taskProcedureService.update(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.update.success", args: ["TaskProcedure", params.id])
+            redirect(action:'show', id:result.taskProcedureInstance.id)
+            return
+        }
+
+        if(result.error.code == "default.not.found") {
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+            redirect(action:list)
+            return
+        }
+
+        if(result.error.code == "default.optimistic.locking.failure") {
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+            redirect(action:'show', id:result.taskProcedureInstance.id)
+            return
+        }
+
+        def assemblies = assetService.getAssemblies(result.taskProcedureInstance.linkedTask.primaryAsset)
+        render(view:'edit', model:[taskProcedureInstance: result.taskProcedureInstance,
+                                                assemblies: assemblies])
+    }
+
+    def create = {
+
+        if(!params.taskInstance?.id) {
+            flash.errorMessage = "Please select or create a task, then go to the Procedure tab."
+            redirect(controller:"taskDetailed", action:"search")
+            return
+        }
+
+        params.linkedTask = Task.get(params.taskInstance.id)
+
+        // Task already has a taskProcedure.
+        if(params.linkedTask.taskProcedureRevision) {
+            flash.errorMessage = g.message(code: 'default.optimistic.locking.failure')
+            redirect(controller:'taskDetailed',
+                            action:'show',
+                            id:params.linkedTask.id,
+                            params:[showTab:"showProcedureTab"])
+            return
+        }
+
+        // Task does not have a primaryAsset.
+        if(!params.linkedTask?.primaryAsset) {
+            flash.errorMessage = "Please set a Primary Asset first, then go to the Procedure tab."
+            redirect(controller:"taskDetailed", action:"show", id:params.linkedTask?.id)
+            return
+        }
+
+        def taskProcedureInstance = new TaskProcedure()
+        taskProcedureInstance.properties = params
+
+        // Populate a couple of maintenanceActions for the first assembly.
+        def assemblies = assetService.getAssemblies(params.linkedTask.primaryAsset)
+        if(assemblies) {
+            def assembly = assemblies[0]
+            def ma = taskProcedureInstance.maintenanceActionLazyList.get(0)
+            ma.assetSubItem = assembly
+            ma.procedureStepNumber = 10
+            ma = taskProcedureInstance.maintenanceActionLazyList.get(1)
+            ma.assetSubItem = assembly
+            ma.procedureStepNumber = 20
+        }
+
+        return ['taskProcedureInstance':taskProcedureInstance, 'assemblies': assemblies]
+    }
+
+    def save = {
+        def result = taskProcedureService.save(params)
+
+        if(!result.error) {
+            flash.message = g.message(code: "default.create.success", args: ["TaskProcedure", result.taskProcedureInstance.id])
+            redirect(action:'show', id:result.taskProcedureInstance.id)
+            return
+        }
+
+        // Task already has a taskProcedure.
+        if(result.error.code == "default.optimistic.locking.failure") {
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+            redirect(controller:'taskDetailed',
+                            action:'show',
+                            id:params.linkedTask.id,
+                            params:[showTab:"showProcedureTab"])
+            return
+        }
+
+        def assemblies = assetService.getAssemblies(result.taskProcedureInstance.linkedTask.primaryAsset)
+        render(view:'create', model:[taskProcedureInstance: result.taskProcedureInstance,
+                                                    assemblies: assemblies])
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskRecurringScheduleDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskRecurringScheduleDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskRecurringScheduleDetailedController.groovy	(revision 875)
@@ -0,0 +1,103 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
+class TaskRecurringScheduleDetailedController extends BaseController {
+
+    def taskRecurringScheduleService
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ taskRecurringScheduleInstanceList: TaskRecurringSchedule.list( params ), taskRecurringScheduleInstanceTotal: TaskRecurringSchedule.count() ]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def show = {
+        def taskRecurringScheduleInstance = TaskRecurringSchedule.get( params.id )
+
+        if(!taskRecurringScheduleInstance) {
+            flash.message = "Recurring Schedule not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ taskRecurringScheduleInstance : taskRecurringScheduleInstance ] }
+    }
+
+    def delete = {
+        def taskRecurringScheduleInstance = TaskRecurringSchedule.get( params.id )
+        if(taskRecurringScheduleInstance) {
+            try {
+                taskRecurringScheduleInstance.delete(flush: true)
+                flash.message = "Recurring Schedule ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "Recurring Schedule ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "Recurring Schedule not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def taskRecurringScheduleInstance = TaskRecurringSchedule.get( params.id )
+
+        if(!taskRecurringScheduleInstance) {
+            flash.message = "Recurring Schedule not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ taskRecurringScheduleInstance : taskRecurringScheduleInstance]
+        }
+    }
+
+    def update = {
+
+        if(!TaskRecurringSchedule.exists(params.id)) {
+            flash.message = "Recurring Schedule not found with id ${params.id}"
+            redirect(action: 'list')
+        }
+
+        def result = taskRecurringScheduleService.update(params)
+
+        if(!result.error) {
+                flash.message = "Recurring Schedule ${params.id} updated"
+                redirect(action: 'show', id: result.taskRecurringScheduleInstance.id)
+        }
+        else {
+            render(view:'edit',model:[taskRecurringScheduleInstance: result.taskRecurringScheduleInstance.attach()])
+        }
+
+    }
+
+    def create = {
+        if(!params.task?.id || !Task.exists(params.task?.id)) {
+            flash.message = "Please select a task, then create a recurring schedule for it."
+            redirect(controller:"taskDetailed", action:"search")
+            return
+        }
+        def taskRecurringScheduleInstance = new TaskRecurringSchedule(params)
+        return [taskRecurringScheduleInstance: taskRecurringScheduleInstance]
+    }
+
+    def save = {
+        def result = taskRecurringScheduleService.create(params)
+
+        if(!result.error) {
+            flash.message = "Recurring Schedule ${result.taskRecurringScheduleInstance.id} created."
+            redirect(action:show, id: result.taskRecurringScheduleInstance.id)
+        }
+        else {
+            render(view:'create',model:[taskRecurringScheduleInstance: result.taskRecurringScheduleInstance])
+        }
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskStatusController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskStatusController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskStatusController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class TaskStatusController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ taskStatusInstanceList: TaskStatus.list( params ), taskStatusInstanceTotal: TaskStatus.count() ]
+    }
+
+    def show = {
+        def taskStatusInstance = TaskStatus.get( params.id )
+
+        if(!taskStatusInstance) {
+            flash.message = "TaskStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ taskStatusInstance : taskStatusInstance ] }
+    }
+
+    def delete = {
+        def taskStatusInstance = TaskStatus.get( params.id )
+        if(taskStatusInstance) {
+            try {
+                taskStatusInstance.delete(flush:true)
+                flash.message = "TaskStatus ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "TaskStatus ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "TaskStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def taskStatusInstance = TaskStatus.get( params.id )
+
+        if(!taskStatusInstance) {
+            flash.message = "TaskStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ taskStatusInstance : taskStatusInstance ]
+        }
+    }
+
+    def update = {
+        def taskStatusInstance = TaskStatus.get( params.id )
+        if(taskStatusInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(taskStatusInstance.version > version) {
+                    
+                    taskStatusInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[taskStatusInstance:taskStatusInstance])
+                    return
+                }
+            }
+            taskStatusInstance.properties = params
+            if(!taskStatusInstance.hasErrors() && taskStatusInstance.save(flush: true)) {
+                flash.message = "TaskStatus ${params.id} updated"
+                redirect(action:show,id:taskStatusInstance.id)
+            }
+            else {
+                render(view:'edit',model:[taskStatusInstance:taskStatusInstance])
+            }
+        }
+        else {
+            flash.message = "TaskStatus not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def taskStatusInstance = new TaskStatus()
+        taskStatusInstance.properties = params
+        return ['taskStatusInstance':taskStatusInstance]
+    }
+
+    def save = {
+        def taskStatusInstance = new TaskStatus(params)
+        if(!taskStatusInstance.hasErrors() && taskStatusInstance.save(flush: true)) {
+            flash.message = "TaskStatus ${taskStatusInstance.id} created"
+            redirect(action:show,id:taskStatusInstance.id)
+        }
+        else {
+            render(view:'create',model:[taskStatusInstance:taskStatusInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/TaskTypeController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/TaskTypeController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/TaskTypeController.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+class TaskTypeController extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ taskTypeInstanceList: TaskType.list( params ), taskTypeInstanceTotal: TaskType.count() ]
+    }
+
+    def show = {
+        def taskTypeInstance = TaskType.get( params.id )
+
+        if(!taskTypeInstance) {
+            flash.message = "TaskType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ taskTypeInstance : taskTypeInstance ] }
+    }
+
+    def delete = {
+        def taskTypeInstance = TaskType.get( params.id )
+        if(taskTypeInstance) {
+            try {
+                taskTypeInstance.delete(flush:true)
+                flash.message = "TaskType ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "TaskType ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "TaskType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def taskTypeInstance = TaskType.get( params.id )
+
+        if(!taskTypeInstance) {
+            flash.message = "TaskType not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ taskTypeInstance : taskTypeInstance ]
+        }
+    }
+
+    def update = {
+        def taskTypeInstance = TaskType.get( params.id )
+        if(taskTypeInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(taskTypeInstance.version > version) {
+                    
+                    taskTypeInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[taskTypeInstance:taskTypeInstance])
+                    return
+                }
+            }
+            taskTypeInstance.properties = params
+            if(!taskTypeInstance.hasErrors() && taskTypeInstance.save(flush: true)) {
+                flash.message = "TaskType ${params.id} updated"
+                redirect(action:show,id:taskTypeInstance.id)
+            }
+            else {
+                render(view:'edit',model:[taskTypeInstance:taskTypeInstance])
+            }
+        }
+        else {
+            flash.message = "TaskType not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def taskTypeInstance = new TaskType()
+        taskTypeInstance.properties = params
+        return ['taskTypeInstance':taskTypeInstance]
+    }
+
+    def save = {
+        def taskTypeInstance = new TaskType(params)
+        if(!taskTypeInstance.hasErrors() && taskTypeInstance.save(flush: true)) {
+            flash.message = "TaskType ${taskTypeInstance.id} created"
+            redirect(action:show,id:taskTypeInstance.id)
+        }
+        else {
+            render(view:'create',model:[taskTypeInstance:taskTypeInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/controllers/UnitOfMeasureDetailedController.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/controllers/UnitOfMeasureDetailedController.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/controllers/UnitOfMeasureDetailedController.groovy	(revision 875)
@@ -0,0 +1,110 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
+class UnitOfMeasureDetailedController extends BaseController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ unitOfMeasureInstanceList: UnitOfMeasure.list( params ), unitOfMeasureInstanceTotal: UnitOfMeasure.count() ]
+    }
+
+    def show = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Show)
+            params.action='show'
+
+        def unitOfMeasureInstance = UnitOfMeasure.get( params.id )
+
+        if(!unitOfMeasureInstance) {
+            flash.message = "UnitOfMeasure not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else { return [ unitOfMeasureInstance : unitOfMeasureInstance ] }
+    }
+
+    def delete = {
+        def unitOfMeasureInstance = UnitOfMeasure.get( params.id )
+        if(unitOfMeasureInstance) {
+            try {
+                unitOfMeasureInstance.delete(flush:true)
+                flash.message = "UnitOfMeasure ${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "UnitOfMeasure ${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "UnitOfMeasure not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+
+        // In the case of an actionSubmit button, rewrite action name from 'index'.
+        if(params._action_Edit)
+            params.action='edit'
+
+        def unitOfMeasureInstance = UnitOfMeasure.get( params.id )
+
+        if(!unitOfMeasureInstance) {
+            flash.message = "UnitOfMeasure not found with id ${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ unitOfMeasureInstance : unitOfMeasureInstance ]
+        }
+    }
+
+    def update = {
+        def unitOfMeasureInstance = UnitOfMeasure.get( params.id )
+        if(unitOfMeasureInstance) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(unitOfMeasureInstance.version > version) {
+                    
+                    unitOfMeasureInstance.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[unitOfMeasureInstance:unitOfMeasureInstance])
+                    return
+                }
+            }
+            unitOfMeasureInstance.properties = params
+            if(!unitOfMeasureInstance.hasErrors() && unitOfMeasureInstance.save(flush: true)) {
+                flash.message = "UnitOfMeasure ${params.id} updated"
+                redirect(action:show,id:unitOfMeasureInstance.id)
+            }
+            else {
+                render(view:'edit',model:[unitOfMeasureInstance:unitOfMeasureInstance])
+            }
+        }
+        else {
+            flash.message = "UnitOfMeasure not found with id ${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def unitOfMeasureInstance = new UnitOfMeasure()
+        unitOfMeasureInstance.properties = params
+        return ['unitOfMeasureInstance':unitOfMeasureInstance]
+    }
+
+    def save = {
+        def unitOfMeasureInstance = new UnitOfMeasure(params)
+        if(!unitOfMeasureInstance.hasErrors() && unitOfMeasureInstance.save(flush: true)) {
+            flash.message = "UnitOfMeasure ${unitOfMeasureInstance.id} created"
+            redirect(action:show,id:unitOfMeasureInstance.id)
+        }
+        else {
+            render(view:'create',model:[unitOfMeasureInstance:unitOfMeasureInstance])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Address.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Address.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Address.groovy	(revision 875)
@@ -0,0 +1,36 @@
+class Address {
+
+    AddressType addressType
+
+    Supplier supplier
+    Person person
+    Site site
+
+    String street1 = ''
+    String street2 = ''
+    String city = ''
+    String state = ''
+    String postCode = ''
+    String country = ''
+
+//     hasMany = []
+
+    static belongsTo = [Supplier, Person, Site]
+
+    static constraints = {
+        street1(blank:false,maxSize:50)
+        street2(maxSize:50)
+        city(blank:false,maxSize:50)
+        state(blank:false,maxSize:50)
+        postCode(blank:false,maxSize:50)
+        country(blank:false,maxSize:50)
+        supplier(nullable:true)
+        person(nullable:true)
+        site(nullable:true)
+    }
+
+    String toString() {
+        "${this.addressType}: ${this.street1}, ${this.city}"
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/AddressType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/AddressType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/AddressType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class AddressType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+//     static hasMany = [ : ]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/AppConfig.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/AppConfig.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/AppConfig.groovy	(revision 875)
@@ -0,0 +1,19 @@
+/**
+ * Domain class that stores various application configuration (settings) in the database.
+ * Use AppConfigService to interact with the instances.
+ */
+class AppConfig {
+    String name
+    String value
+    String description = ''
+
+    static constraints = {
+        name(maxSize:100,unique:true,blank:false)
+        value(maxSize:500,blank:false)
+        description(maxSize:500)
+    }
+
+    String toString() {
+        "${this.name} = ${this.value}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Asset.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Asset.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Asset.groovy	(revision 875)
@@ -0,0 +1,67 @@
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+
+class Asset {
+
+    Section section
+
+    String name
+    String description = ""
+    String comment = ""
+    boolean isActive = true
+
+    static hasMany = [assetSubItems: AssetSubItem,
+                                    maintenanceActions: MaintenanceAction,
+                                    assetExtendedAttributes: AssetExtendedAttribute]
+
+    static belongsTo = [Section]
+
+    static constraints = {
+        name(maxSize:50, unique:true, blank:false)
+        description(maxSize:75)
+        comment(maxSize:500)
+        isActive()
+        section()
+    }
+
+    static mapping = {
+        assetSubItems(batchSize:1000)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+
+    static searchable = {
+        root false // only index as a component of InventoryItem.
+        only = ['name', 'description', 'comment']
+    }
+
+    def afterUpdate = {
+        // Update the Inventory searchable index, since cascading in searchable-0.5.5 is broken.
+        if(ConfigurationHolder.config.appSearchable.cascadeOnUpdate) {
+            try {
+                InventoryIndexJob.triggerNow(['calledBy':'Asset afterUpdate{}'])
+            }
+            catch(e) {log.error e}
+        } // if
+    } // afterUpdate
+
+    //  This additional setter is used to convert the checkBoxList string or string array
+    //  of ids selected to the corresponding domain objects.
+    public void setAssetSubItemsFromCheckBoxList(ids) {
+        def idList = []
+        if(ids instanceof String) {
+                if(ids.isInteger())
+                    idList << ids.toLong()
+        }
+        else {
+            ids.each() {
+                if(it.isInteger())
+                    idList << it.toLong()
+            }
+        }
+        this.assetSubItems = idList.collect { AssetSubItem.get( it ) }
+    }
+
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/AssetExtendedAttribute.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/AssetExtendedAttribute.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/AssetExtendedAttribute.groovy	(revision 875)
@@ -0,0 +1,22 @@
+class AssetExtendedAttribute {
+
+    ExtendedAttributeType extendedAttributeType
+    Asset asset
+
+    String value
+    boolean isActive = true
+
+//     static hasMany = []
+
+    static belongsTo = [Asset]
+
+    static constraints = {
+        value(blank:false, maxSize:100)
+        isActive()
+    }
+
+    String toString() {
+        "${extendedAttributeType.name}: ${this.value}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/AssetSubItem.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/AssetSubItem.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/AssetSubItem.groovy	(revision 875)
@@ -0,0 +1,33 @@
+class AssetSubItem {
+
+    AssetSubItem parentItem
+
+    String name
+    String description = ""
+    String comment = ""
+    boolean isActive = true
+
+    static hasMany = [assets: Asset,
+                                subItems: AssetSubItem,
+                                maintenanceActions: MaintenanceAction,
+                                assetSubItemExtendedAttributes: AssetSubItemExtendedAttribute]
+
+    static belongsTo = [Asset, AssetSubItem]
+
+    static constraints = {
+        name(maxSize:50, unique:true, blank:false)
+        description(maxSize:75)
+        comment(maxSize:500)
+        isActive()
+        parentItem(nullable:true)
+    }
+
+    static mapping = {
+        subItems(batchSize:1000)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/AssetSubItemExtendedAttribute.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/AssetSubItemExtendedAttribute.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/AssetSubItemExtendedAttribute.groovy	(revision 875)
@@ -0,0 +1,22 @@
+class AssetSubItemExtendedAttribute {
+
+    ExtendedAttributeType extendedAttributeType
+    AssetSubItem assetSubItem
+
+    String value
+    boolean isActive = true
+
+//     static hasMany = []
+
+    static belongsTo = [AssetSubItem]
+
+    static constraints = {
+        value(blank:false, maxSize:100)
+        isActive()
+    }
+
+    String toString() {
+        "${extendedAttributeType.name}: ${this.value}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/AssignedGroup.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/AssignedGroup.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/AssignedGroup.groovy	(revision 875)
@@ -0,0 +1,18 @@
+class AssignedGroup {
+
+    PersonGroup personGroup
+    Task task
+    Integer estimatedHour = 0
+    Integer estimatedMinute = 0
+
+    static constraints = {
+        task()
+        personGroup()
+        estimatedHour(min:0)
+        estimatedMinute(min:0,max:59)
+    }
+
+    String toString() {
+        "${personGroup.name} - ${estimatedHour}h : ${estimatedMinute}min"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/AssignedPerson.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/AssignedPerson.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/AssignedPerson.groovy	(revision 875)
@@ -0,0 +1,18 @@
+class AssignedPerson {
+
+    Person person
+    Task task
+    Integer estimatedHour = 0
+    Integer estimatedMinute = 0
+
+    static constraints = {
+        task()
+        person()
+        estimatedHour(min:0)
+        estimatedMinute(min:0,max:59)
+    }
+
+    String toString() {
+        "${person.firstName} ${person.lastName} - ${estimatedHour}h : ${estimatedMinute}min"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Authority.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Authority.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Authority.groovy	(revision 875)
@@ -0,0 +1,18 @@
+class Authority {
+
+    static hasMany = [persons: Person]
+
+    /** description */
+    String description
+    /** ROLE String */
+    String authority
+
+    static constraints = {
+        authority(blank: false, unique: true)
+        description()
+    }
+
+    String toString() {
+        "${this.authority}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/ConditionSeverity.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/ConditionSeverity.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/ConditionSeverity.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class ConditionSeverity {
+    String code
+    String recommendation = ""
+    boolean isActive = true
+
+//     static hasMany = []
+
+    static constraints = {
+        code(maxSize:5,unique:true,blank:false)
+        recommendation(maxSize:25,blank:false)
+    }
+
+    String toString() {
+        "${this.code} - ${this.recommendation}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Contact.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Contact.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Contact.groovy	(revision 875)
@@ -0,0 +1,27 @@
+class Contact {
+
+    ContactType contactType
+
+    Supplier supplier
+    Person person
+    Site site
+
+    String value
+
+//     hasMany = []
+
+    static belongsTo = [Supplier, Person, Site]
+
+    static constraints = {
+        value(maxSize:50)
+
+        supplier(nullable:true)
+        person(nullable:true)
+        site(nullable:true)
+    }
+
+    String toString() {
+        "${this.contactType}: ${this.value}"
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/ContactType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/ContactType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/ContactType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class ContactType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+//     static hasMany = [ : ]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/CostCode.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/CostCode.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/CostCode.groovy	(revision 875)
@@ -0,0 +1,32 @@
+class CostCode {
+
+    PurchasingGroup purchasingGroup
+
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [inventoryItemPurchases: InventoryItemPurchase]
+
+    static constraints = {
+        name(blank:false, maxSize:50, validator: {val, obj ->
+            // Name must be unique for a purchasingGroup.
+            def list = CostCode.withCriteria {
+                eq('purchasingGroup', obj.purchasingGroup)
+                eq('name', obj.name)
+                if(obj.id)
+                    notEqual('id', obj.id)
+            }
+            if(list.size() > 0)
+                return 'not.unique.for.purchasing.group'
+            // Success.
+            return true
+        })
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}.${this.purchasingGroup}"
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Department.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Department.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Department.groovy	(revision 875)
@@ -0,0 +1,25 @@
+class Department {
+
+    String name
+    String description = ""
+    String comment = ""
+    boolean isActive = true
+
+    static hasMany = [sections: Section,
+                                departmentExtendedAttributes: DepartmentExtendedAttribute,
+                                persons: Person]
+
+//     static belongsTo = []
+
+    static constraints = {
+        name(maxSize:50, unique:true, blank:false)
+        description(maxSize:75)
+        comment(maxSize:500)
+        isActive()
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/DepartmentExtendedAttribute.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/DepartmentExtendedAttribute.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/DepartmentExtendedAttribute.groovy	(revision 875)
@@ -0,0 +1,22 @@
+class DepartmentExtendedAttribute {
+
+    ExtendedAttributeType extendedAttributeType
+    Department department
+
+    String value
+    boolean isActive = true
+
+//     static hasMany = []
+
+    static belongsTo = [Department]
+
+    static constraints = {
+        value(maxSize:100)
+        isActive()
+    }
+
+    String toString() {
+        "${extendedAttributeType.name}: ${this.value}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/DocumentReference.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/DocumentReference.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/DocumentReference.groovy	(revision 875)
@@ -0,0 +1,27 @@
+class DocumentReference {
+
+    String name
+    String location
+
+    Boolean toBeDeleted
+    Boolean isNew
+    static transients = [ 'toBeDeleted', 'isNew' ]
+
+//     static hasMany = []
+
+    static belongsTo = [TaskProcedure, TaskProcedureRevision]
+
+    static mapping = {
+        batchSize 10
+    }
+
+    static constraints = {
+        name(blank:false,maxSize:75)
+        location(blank:false,maxSize:500)
+    }
+
+    String toString() {
+        "${this.name} - ${this.location}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/Entry.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Entry.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Entry.groovy	(revision 875)
@@ -0,0 +1,38 @@
+class Entry {
+    Person enteredBy
+    Task task
+    EntryType entryType
+    ConditionSeverity highestSeverity
+    ProductionReference productionReference
+
+    String comment
+    Date dateDone = new Date()
+    Date dateEntered = new Date()
+    Integer durationHour = 0
+    Integer durationMinute = 0
+
+    static belongsTo = [EntryType, Task, Person]
+
+    static constraints = {
+        task()
+        comment(blank:false,maxSize:500)
+        dateDone()
+        durationHour(min:0,max:16)
+        durationMinute(min:0,max:59)
+        productionReference(nullable: true)
+        // Nullable unless PM Entry Type.
+        highestSeverity(nullable:true, validator: {val, obj ->
+            if(val == null && (obj.entryType.id == 6))
+                return 'not.nullable.for.pm.entry'
+        })
+    }
+
+    String toString() {
+        "${this.comment} - ${this.enteredBy}, ${this.dateDone}"
+    }
+
+    String toShortString() {
+        "${enteredBy.firstName} ${enteredBy.lastName} - ${durationHour}h : ${durationMinute}min"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/EntryType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/EntryType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/EntryType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class EntryType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [entries: Entry]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/ExtendedAttributeType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/ExtendedAttributeType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/ExtendedAttributeType.groovy	(revision 875)
@@ -0,0 +1,21 @@
+class ExtendedAttributeType {
+
+    String name
+    String description = ""
+    boolean isActive = true
+
+//     static hasMany = []
+
+//     static belongsTo = []
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+        isActive()
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/Image.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Image.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Image.groovy	(revision 875)
@@ -0,0 +1,52 @@
+class Image implements Comparable {
+
+    Picture picture
+    Integer size
+    byte[] data
+    String contentType
+    Integer width
+    Integer height
+    Date dateCreated = new Date()
+    Date lastUpdated = new Date()
+
+    static belongsTo = [ Picture ]
+
+    static mapping = {
+        picture index: 'images_index', unique: true
+        size index: 'images_index', unique: true
+        data type: 'binary'
+    }
+
+    static constraints = {
+        data(maxSize: MAX_SIZE)
+    }
+
+    static final Integer MAX_SIZE = 10 * 1024 * 1024
+
+    static final Integer Original = 1
+    static final Integer Large = 2
+    static final Integer Medium = 3
+    static final Integer Small = 4
+
+    static final Integer[] Widths =  [ 0, 0, 500, 250, 100 ]
+    static final Integer[] Heights = [ 0, 0, 500, 250, 100 ]
+
+    static final String[] Names = [ '', 'Original', 'Large', 'Medium', 'Small' ]
+
+    int compareTo(obj) {
+        size.compareTo(obj.size)
+    }
+
+    String filename() {
+        Image.filename(picture.id, size)
+    }
+
+    static String filename(long id, int size) {
+        if (size == Original) {
+            return "${id}-${Names[size]}.jpg"
+        }
+        else {
+            return "${id}-${Names[size]}.png"
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryGroup.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryGroup.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryGroup.groovy	(revision 875)
@@ -0,0 +1,32 @@
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+
+class InventoryGroup {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [inventoryItems : InventoryItem]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {"${this.name}"}
+
+    static searchable = {
+        root false // only index as a component of InventoryItem.
+        only = ['name']
+    }
+
+    def afterUpdate = {
+        // Update the Inventory searchable index, since cascading in searchable-0.5.5 is broken.
+        if(ConfigurationHolder.config.appSearchable.cascadeOnUpdate) {
+            try {
+                InventoryIndexJob.triggerNow(['calledBy':'InventoryGroup afterUpdate{}'])
+            }
+            catch(e) {log.error e}
+        } // if
+    } // afterUpdate
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryItem.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryItem.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryItem.groovy	(revision 875)
@@ -0,0 +1,96 @@
+class  InventoryItem {
+    InventoryGroup inventoryGroup
+    InventoryType inventoryType
+    UnitOfMeasure unitOfMeasure
+    InventoryLocation inventoryLocation
+    Picture picture
+    Supplier preferredSupplier
+    String name
+    String description = ""
+    String comment = ""
+    BigDecimal estimatedUnitPriceAmount
+    Currency estimatedUnitPriceCurrency
+    String suppliersPartNumber
+    Integer unitsInStock = 0
+    Integer reorderPoint = 0
+    Integer reorderQuantity = 1
+    boolean isActive = true
+    boolean isObsolete = false
+    boolean enableReorderListing = true
+
+    static mapping = {
+        picture cascade: 'all-delete-orphan', lazy: true, inverse: true
+    }
+
+    static hasMany = [spareFor: Asset,
+                                    inventoryMovements: InventoryMovement,
+                                    alternateSuppliers: Supplier]
+
+//     static belongsTo = []
+
+    static constraints = {
+        picture(nullable:true)
+        name(unique:true, blank:false, maxSize:50)
+        description(maxSize:255)
+        comment(maxSize:500)
+        unitsInStock(min:0)
+        unitOfMeasure()
+        inventoryLocation()
+        inventoryGroup()
+        inventoryType()
+        isActive()
+        isObsolete()
+        enableReorderListing()
+        reorderPoint(min:0)
+        reorderQuantity(min:1)
+        estimatedUnitPriceAmount(nullable:true, max: new BigDecimal(1000000000000))
+        estimatedUnitPriceCurrency(nullable:true)
+        suppliersPartNumber(blank:true, nullable:true, maxSize:50)
+        preferredSupplier(nullable:true)
+    }
+
+    String toString() {"${this.name}"}
+
+    static searchable = {
+        only = ['name', 'description', 'comment', 'isActive', 'isObsolete', 'inventoryLocation', 'inventoryGroup', 'spareFor']
+        //name boost: 1.5
+        inventoryLocation component: true
+        inventoryGroup component: true
+        spareFor component: true
+    }
+
+    //  This additional setter is used to convert the checkBoxList string or string array
+    //  of ids selected to the corresponding domain objects.
+    public void setAlternateSuppliersFromCheckBoxList(ids) {
+        def idList = []
+        if(ids instanceof String) {
+                if(ids.isInteger())
+                    idList << ids.toLong()
+        }
+        else {
+            ids.each() {
+                if(it.isInteger())
+                    idList << it.toLong()
+            }
+        }
+        this.alternateSuppliers = idList.collect { Supplier.get( it ) }
+    }
+
+    //  This additional setter is used to convert the checkBoxList string or string array
+    //  of ids selected to the corresponding domain objects.
+    public void setSpareForFromCheckBoxList(ids) {
+        def idList = []
+        if(ids instanceof String) {
+                if(ids.isInteger())
+                    idList << ids.toLong()
+        }
+        else {
+            ids.each() {
+                if(it.isInteger())
+                    idList << it.toLong()
+            }
+        }
+        this.spareFor = idList.collect { Asset.get( it ) }
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryItemPurchase.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryItemPurchase.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryItemPurchase.groovy	(revision 875)
@@ -0,0 +1,58 @@
+class InventoryItemPurchase {
+
+    Person enteredBy
+    Person lastUpdatedBy
+    InventoryItem inventoryItem
+    CostCode costCode
+    InventoryItemPurchaseType inventoryItemPurchaseType
+    Supplier supplier
+    TaskBudgetStatus taskBudgetStatus
+
+    Date date = new Date()
+    Date lastUpdated // autoTimestamp
+    Date dateCreated // autoTimestamp
+
+    Integer quantity
+    String purchaseOrderNumber = ''
+    BigDecimal orderValueAmount
+    Currency orderValueCurrency
+    String invoiceNumber = ''
+    String comment = ""
+
+    Boolean receivedComplete = false
+    Boolean invoicePaymentApproved = false
+
+//     hasMany = []
+
+    static belongsTo = [InventoryItem]
+
+    static constraints = {
+        quantity(min:0)
+        purchaseOrderNumber(blank:false, maxSize:50, validator: {val, obj ->
+            // For orders the purchaseOrderNumber must be unique for an inventoryItem.
+            if(obj.inventoryItemPurchaseType.id == 1L) {
+                def list = InventoryItemPurchase.withCriteria {
+                    eq('inventoryItem', obj.inventoryItem)
+                    eq('purchaseOrderNumber', obj.purchaseOrderNumber)
+                    eq('inventoryItemPurchaseType', obj.inventoryItemPurchaseType)
+                    if(obj.id)
+                        notEqual('id', obj.id)
+                }
+                if(list.size() > 0)
+                    return 'not.unique.for.inventory.item.order'
+            }
+            // Success.
+            return true
+        })
+        invoiceNumber(maxSize:50)
+        orderValueAmount(max: new BigDecimal(1000000000000))
+        orderValueCurrency()
+        comment(maxSize:255)
+        lastUpdatedBy(nullable: true)
+    }
+
+    String toString() {
+        "${this.quantity} x ${inventoryItem} - ${this.inventoryItemPurchaseType} "
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryItemPurchaseType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryItemPurchaseType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryItemPurchaseType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class InventoryItemPurchaseType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+//     static hasMany = []
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryLocation.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryLocation.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryLocation.groovy	(revision 875)
@@ -0,0 +1,36 @@
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+
+class InventoryLocation {
+
+    InventoryStore inventoryStore
+    String name
+    Boolean isActive = true
+
+    static hasMany = [inventoryItems: InventoryItem]
+
+//     static belongsTo = [InventoryStore]
+
+    static constraints = {
+        name(maxSize:50)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+
+    static searchable = {
+        root false // only index as a component of InventoryItem.
+        only = ['name']
+    }
+
+    def afterUpdate = {
+        // Update the Inventory searchable index, since cascading in searchable-0.5.5 is broken.
+        if(ConfigurationHolder.config.appSearchable.cascadeOnUpdate) {
+            try {
+                InventoryIndexJob.triggerNow(['calledBy':'InventoryLocation afterUpdate{}'])
+            }
+            catch(e) {log.error e}
+        } // if
+    } // afterUpdate
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryMovement.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryMovement.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryMovement.groovy	(revision 875)
@@ -0,0 +1,24 @@
+class InventoryMovement {
+    Person person
+    InventoryItem inventoryItem
+    InventoryMovementType inventoryMovementType
+    Task task
+    Integer quantity
+    Date date = new Date()
+
+    // We do not want deletion of inventory items to cascade.
+    //static belongsTo = [InventoryItem]
+
+    static constraints = {
+        inventoryItem()
+        quantity(min:1)
+        inventoryMovementType()
+        task(nullable:true)
+        person()
+        date()
+    }
+
+    String toString() {
+        "${this.quantity} ${inventoryMovementType.name} on ${date.format('EEE, dd-MMM-yyyy')} by ${person}."
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryMovementType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryMovementType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryMovementType.groovy	(revision 875)
@@ -0,0 +1,19 @@
+class InventoryMovementType {
+    String name
+    String description = ""
+    boolean incrementsInventory = false
+    boolean isActive = true
+
+    static hasMany = [inventoryMovements: InventoryMovement]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+        incrementsInventory()
+        isActive()
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryStore.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryStore.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryStore.groovy	(revision 875)
@@ -0,0 +1,20 @@
+class InventoryStore {
+
+    Site site
+    String name
+    String description = ""
+    Boolean isActive = true
+
+    static hasMany = [inventoryLocations: InventoryLocation]
+
+    static belongsTo = [Site]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/InventoryType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/InventoryType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/InventoryType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class InventoryType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [inventoryItems: InventoryItem]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/MaintenanceAction.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/MaintenanceAction.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/MaintenanceAction.groovy	(revision 875)
@@ -0,0 +1,38 @@
+class MaintenanceAction {
+
+    MaintenancePolicy maintenancePolicy
+    Section section
+    Asset asset
+    AssetSubItem assetSubItem
+
+    String description
+    String pageRef = ""
+    Integer procedureStepNumber
+
+    Boolean toBeDeleted
+    Boolean isNew
+    static transients = [ 'toBeDeleted', 'isNew' ]
+
+//     static hasMany = []
+
+    static mapping = {
+        batchSize 10
+    }
+
+    static belongsTo = [TaskProcedure, TaskProcedureRevision]
+
+    static constraints = {
+        section(nullable:true)
+        asset(nullable:true)
+        assetSubItem()
+        maintenancePolicy(nullable:true)
+        procedureStepNumber()
+        description(blank:false,maxSize:100)
+        pageRef(maxSize:25)
+    }
+
+    String toString() {
+        "${this.description}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/MaintenancePolicy.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/MaintenancePolicy.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/MaintenancePolicy.groovy	(revision 875)
@@ -0,0 +1,21 @@
+class MaintenancePolicy {
+
+    String name
+    String description = ""
+    boolean isActive = true
+
+//     static hasMany = [maintenanceActions: MaintenanceAction]
+
+//     static belongsTo = []
+
+    static constraints = {
+        name(maxSize:50, unique:true, blank:false)
+        description(maxSize:100)
+        isActive()
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/Period.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Period.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Period.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class Period {
+
+    String period
+    boolean isActive = true
+
+//     static belongsTo = []
+
+//     static constraints = {
+// 
+//     }
+
+    String toString() {
+        "${this.period}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/Person.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Person.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Person.groovy	(revision 875)
@@ -0,0 +1,88 @@
+class Person {
+    static transients = ['pass']
+    static hasMany = [authorities: Authority,
+                        personGroups: PersonGroup,
+                        taskModifications: TaskModification,
+                        entries: Entry,
+                        tasks: Task,
+                        contacts: Contact,
+                        addresses: Address,
+                        purchasingGroups: PurchasingGroup]
+
+    static belongsTo = [Authority]
+
+    Department department
+
+    String loginName
+    String firstName
+    String lastName
+    String employeeID = ''
+
+    /* Set after login by 'welcome' action, default to 12 hours, aka "sess.setMaxInactiveInterval(seconds) */
+    Integer sessionTimeout = 43200
+
+    /** MD5 Password */
+    String password
+
+    /** enabled */
+    boolean isActive = true
+
+    /** description */
+    String description = ''
+
+    /** plain password to create a MD5 password */
+    String pass
+
+    static constraints = {
+        loginName(blank: false, unique: true, minSize:4) //minSize:7
+        firstName(blank: false)
+        lastName(blank: false)
+        employeeID()
+        description()
+        department(nullable:true)
+        isActive()
+        //Enforcing minSize on password does not work since "" gets encoded to a string.
+        password(blank: false)
+        //So we need to use pass for validation then encode it for above.
+        pass(blank: false, minSize:4) //minSize:7
+        sessionTimeout(min:60, max:43200)
+    }
+
+    //Overriding the default toString method
+    String toString() {"${this.firstName} ${this.lastName}"}
+
+    //  This additional setter is used to convert the checkBoxList string or string array
+    //  of ids selected to the corresponding domain objects.
+    public void setPersonGroupsFromCheckBoxList(ids) {
+        def idList = []
+        if(ids instanceof String) {
+                if(ids.isInteger())
+                    idList << ids.toLong()
+        }
+        else {
+            ids.each() {
+                if(it.isInteger())
+                    idList << it.toLong()
+            }
+        }
+        this.personGroups = idList.collect { PersonGroup.get( it ) }
+    }
+
+    //  This additional setter is used to convert the checkBoxList string or string array
+    //  of ids selected to the corresponding domain objects.
+    public void setPurchasingGroupsFromCheckBoxList(ids) {
+        def idList = []
+        if(ids instanceof String) {
+                if(ids.isInteger())
+                    idList << ids.toLong()
+        }
+        else {
+            ids.each() {
+                if(it.isInteger())
+                    idList << it.toLong()
+            }
+        }
+        this.purchasingGroups = idList.collect { PurchasingGroup.get( it ) }
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/domain/PersonGroup.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/PersonGroup.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/PersonGroup.groovy	(revision 875)
@@ -0,0 +1,19 @@
+class PersonGroup {
+    PersonGroupType personGroupType
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [persons : Person]
+
+    static belongsTo = [Person]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/PersonGroupType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/PersonGroupType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/PersonGroupType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class PersonGroupType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [personGroups : PersonGroup]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Picture.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Picture.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Picture.groovy	(revision 875)
@@ -0,0 +1,32 @@
+class Picture {
+
+    InventoryItem inventoryItem
+    SortedSet images
+    String file
+    Integer operation
+    String contentType
+    Integer width
+    Integer height
+    Date dateCreated = new Date()
+    Date lastUpdated = new Date()
+
+    static belongsTo = [ InventoryItem ]
+    static hasMany = [ images : Image ]
+
+    static transients = [ 'file', 'operation']
+
+    static constraints = {
+    }
+
+    static mapping = {
+        images cascade: 'all-delete-orphan', inverse: true
+    }
+
+    static final Integer NoOp = 0
+    static final Integer RotateClockWise90 = 1
+    static final Integer RotateAntiClockWise90 = 2
+    static final Integer Rotate180 = 3
+    static final Integer Flip = 4
+    static final Integer Flop = 5
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/ProductionReference.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/ProductionReference.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/ProductionReference.groovy	(revision 875)
@@ -0,0 +1,20 @@
+class ProductionReference {
+
+    String name
+    String description = ""
+    Boolean isActive = true
+
+//     static hasMany = []
+
+//     static belongsTo = []
+
+    static constraints = {
+        name(maxSize:50, unique:true, blank:false)
+        description(maxSize:75)
+        isActive()
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/PurchasingGroup.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/PurchasingGroup.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/PurchasingGroup.groovy	(revision 875)
@@ -0,0 +1,19 @@
+class PurchasingGroup {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [persons : Person,
+                                    costCodes: CostCode]
+
+    static belongsTo = [Person]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Section.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Section.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Section.groovy	(revision 875)
@@ -0,0 +1,32 @@
+class Section {
+
+    Site site
+    Department department
+
+    String name
+    String description = ""
+    String comment = ""
+    boolean isActive = true
+
+    static hasMany = [assets: Asset,
+                                maintenanceActions: MaintenanceAction,
+                                sectionExtendedAttributes: SectionExtendedAttribute]
+
+    static belongsTo = [Site]
+
+    static constraints = {
+        name(maxSize:50, unique:true, blank:false)
+        description(maxSize:75)
+        comment(maxSize:500)
+        isActive()
+    }
+
+    static mapping = {
+        assets(batchSize:1000)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/SectionExtendedAttribute.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/SectionExtendedAttribute.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/SectionExtendedAttribute.groovy	(revision 875)
@@ -0,0 +1,22 @@
+class SectionExtendedAttribute {
+
+    ExtendedAttributeType extendedAttributeType
+    Section section
+
+    String value
+    boolean isActive = true
+
+//     static hasMany = []
+
+    static belongsTo = [Section]
+
+    static constraints = {
+        value(maxSize:100)
+        isActive()
+    }
+
+    String toString() {
+        "${extendedAttributeType.name}: ${this.value}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/Site.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Site.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Site.groovy	(revision 875)
@@ -0,0 +1,30 @@
+class Site {
+
+    String name
+    String description = ""
+    String comment = ""
+    Boolean isActive = true
+
+    static hasMany = [sections: Section,
+                                siteExtendedAttributes: SiteExtendedAttribute,
+                                inventoryStores: InventoryStore,
+                                contacts: Contact,
+                                addresses: Address]
+
+//     static belongsTo = []
+
+    static constraints = {
+        name(maxSize:50, unique:true, blank:false)
+        description(maxSize:75)
+        comment(maxSize:500)
+        isActive()
+    }
+
+    static mapping = {
+        sections(batchSize:1000)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/SiteExtendedAttribute.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/SiteExtendedAttribute.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/SiteExtendedAttribute.groovy	(revision 875)
@@ -0,0 +1,22 @@
+class SiteExtendedAttribute {
+
+    ExtendedAttributeType extendedAttributeType
+    Site site
+
+    String value
+    boolean isActive = true
+
+//     static hasMany = []
+
+    static belongsTo = [Site]
+
+    static constraints = {
+        value(maxSize:100)
+        isActive()
+    }
+
+    String toString() {
+        "${extendedAttributeType.name}: ${this.value}"
+    }
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/Supplier.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Supplier.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Supplier.groovy	(revision 875)
@@ -0,0 +1,20 @@
+class Supplier {
+    SupplierType supplierType
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [contacts: Contact,
+                                    addresses: Address]
+
+//     static belongsTo = []
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/SupplierType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/SupplierType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/SupplierType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class SupplierType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [suppliers: Supplier]
+    
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/Task.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/Task.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/Task.groovy	(revision 875)
@@ -0,0 +1,75 @@
+class Task {
+
+    TaskGroup taskGroup
+    TaskStatus taskStatus
+    TaskPriority taskPriority
+    TaskBudgetStatus taskBudgetStatus
+    TaskType taskType
+    Task parentTask
+    Person leadPerson
+    Site site
+    Section section
+    Asset primaryAsset
+    AssetSubItem assetSubItem
+    TaskRecurringSchedule taskRecurringSchedule
+    TaskProcedureRevision taskProcedureRevision
+    ConditionSeverity highestSeverity
+
+    String description
+    String comment = ""
+    Date targetStartDate = new Date()
+    Date targetCompletionDate = new Date()
+    boolean approved = false
+    boolean trash = false
+    boolean attentionFlag = false
+    boolean safetyRequirement = false
+    boolean regulatoryRequirement = false
+    boolean mandatoryRequirement = false
+    boolean positiveFault = false
+
+    static hasMany = [entries: Entry,
+                        taskModifications: TaskModification,
+                        assignedGroups: AssignedGroup,
+                        assignedPersons: AssignedPerson,
+                        subTasks: Task,
+                        associatedAssets: Asset,
+                        inventoryMovements: InventoryMovement]
+
+    static mappedBy = [taskRecurringSchedule:"task"]
+
+    static mapping = {
+        primaryAsset lazy:false
+    }
+
+    static belongsTo = [TaskGroup, TaskStatus, Task, Person]
+
+    static constraints = {
+        description(blank:false,maxSize:75)
+        comment(maxSize:1000)
+        targetStartDate()
+        targetCompletionDate(validator: {val, obj ->
+            if(val.before(obj.targetStartDate))
+                return 'before.targetStartDate'
+        })
+        leadPerson()
+        taskPriority()
+        taskBudgetStatus()
+        taskStatus()
+        parentTask(nullable:true)
+        site(nullable:true)
+        section(nullable:true)
+        primaryAsset(nullable:true)
+        assetSubItem(nullable:true)
+        taskRecurringSchedule(nullable:true)
+        taskProcedureRevision(nullable:true)
+        highestSeverity(nullable:true)
+    }
+
+    String toString() {
+        def s = "#${this.id} - "
+        if(this.primaryAsset)
+            s += "${primaryAsset.name}: "
+        s += "${this.description}"
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskBudgetStatus.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskBudgetStatus.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskBudgetStatus.groovy	(revision 875)
@@ -0,0 +1,14 @@
+class TaskBudgetStatus {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [tasks : Task]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {"${this.name}"}
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskGroup.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskGroup.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskGroup.groovy	(revision 875)
@@ -0,0 +1,14 @@
+class TaskGroup {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [tasks : Task]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {"${this.name}"}
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskModification.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskModification.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskModification.groovy	(revision 875)
@@ -0,0 +1,21 @@
+class TaskModification {
+    Person person
+    TaskModificationType taskModificationType
+    Task task
+    Date date = new Date()
+    String comment = ""
+
+    static belongsTo = [Person, TaskModificationType, Task]
+
+    static constraints = {
+        person()
+        taskModificationType()
+        task()
+        date()
+        comment()
+    }
+
+    String toString() {
+        "${taskModificationType} on ${date.format('EEE, dd-MMM-yyyy')} by ${person}."
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskModificationType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskModificationType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskModificationType.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class TaskModificationType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [taskModifications : TaskModification]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskPriority.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskPriority.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskPriority.groovy	(revision 875)
@@ -0,0 +1,14 @@
+class TaskPriority {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [tasks : Task]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {"${this.name}"}
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskProcedure.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskProcedure.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskProcedure.groovy	(revision 875)
@@ -0,0 +1,73 @@
+import org.apache.commons.collections.list.LazyList
+import org.apache.commons.collections.FactoryUtils
+
+class TaskProcedure {
+
+    Task linkedTask
+
+    def getDescription() { linkedTask.description }
+    def getAsset() { linkedTask.primaryAsset }
+
+    List maintenanceActions = new ArrayList()
+    List documentReferences = new ArrayList()
+    List revisions = new ArrayList()
+
+    static hasMany = [maintenanceActions: MaintenanceAction,
+                                    documentReferences: DocumentReference,
+                                    revisions: TaskProcedureRevision]
+
+    def getMaintenanceActionLazyList() {
+        return LazyList.decorate(maintenanceActions, FactoryUtils.instantiateFactory(MaintenanceAction.class))
+    }
+
+    def getDocumentReferenceLazyList() {
+        return LazyList.decorate(documentReferences, FactoryUtils.instantiateFactory(DocumentReference.class))
+    }
+
+    // The current revision number is equal to the count of the revisions created.
+    // More efficient than loading the entire revisions list and using size().
+    // WithTransaction is used to allow calling in a transaction however objects
+    // in the current transaction must not trigger DataIntegrityViolationException.
+    def getRevision() {
+        def revision
+        TaskProcedure.withTransaction {
+            revision = TaskProcedureRevision.countByTaskProcedure(this)
+        }
+        return revision
+    }
+
+    // Get a specific revision.
+    def getRevision(revision) {
+        def taskProcedureRevision
+        TaskProcedure.withTransaction {
+            taskProcedureRevision = TaskProcedureRevision.findByTaskProcedureAndRevision(this, revision)
+        }
+        return taskProcedureRevision
+    }
+
+    // Get the latest revision of this procedure.
+    def getLatestRevision() {
+        def taskProcedureRevision
+        TaskProcedure.withTransaction {
+            taskProcedureRevision = TaskProcedureRevision.findByTaskProcedureAndRevision(this, this.revision)
+        }
+        return taskProcedureRevision
+    }
+
+    static mapping = {
+        linkedTask lazy:false
+        revisions batchSize: 10
+        maintenanceActions cascade:"all-delete-orphan"
+        documentReferences cascade:"all-delete-orphan"
+        revisions cascade:"all-delete-orphan"
+    }
+
+//     static belongsTo = []
+
+    static constraints = {
+    }
+
+    String toString() {
+        "${this.id}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskProcedureRevision.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskProcedureRevision.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskProcedureRevision.groovy	(revision 875)
@@ -0,0 +1,62 @@
+import org.apache.commons.collections.list.LazyList
+import org.apache.commons.collections.FactoryUtils
+
+class TaskProcedureRevision {
+
+    Task linkedTask
+
+    TaskProcedure taskProcedure
+    Integer revision
+    Person createdBy
+    Date dateCreated = new Date() // autoTimestamp
+
+    def getDescription() { linkedTask.description }
+    def getAsset() { linkedTask.primaryAsset }
+
+    List maintenanceActions = new ArrayList()
+    List documentReferences = new ArrayList()
+
+    static hasMany = [tasks: Task,
+                                    maintenanceActions: MaintenanceAction,
+                                    documentReferences: DocumentReference]
+
+    def getMaintenanceActionLazyList() {
+        return LazyList.decorate(maintenanceActions, FactoryUtils.instantiateFactory(MaintenanceAction.class))
+    }
+
+    def getDocumentReferenceLazyList() {
+        return LazyList.decorate(documentReferences, FactoryUtils.instantiateFactory(DocumentReference.class))
+    }
+
+    // The taskProcedure holds the procedure id number.
+    def getTaskProcedureId() {
+        taskProcedure.id
+    }
+
+    static mappedBy = [tasks:"taskProcedureRevision"]
+
+    static mapping = {
+        taskProcedure lazy:false
+        linkedTask lazy:false
+        tasks batchSize: 10
+        maintenanceActions cascade:"all-delete-orphan"
+        documentReferences cascade:"all-delete-orphan"
+    }
+
+    static belongsTo = [TaskProcedure]
+
+    static constraints = {
+    }
+
+    String toString() {
+        "${this.id}"
+    }
+
+    def getRevisionDateString() {
+        "${this.revision} -- ${dateCreated.format('EEE, dd-MMM-yyyy')}"
+    }
+
+    def getFullRevisionString() {
+        "${this.revision} -- ${createdBy} on ${dateCreated.format('EEE, dd-MMM-yyyy @ HH:mm')}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskRecurringSchedule.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskRecurringSchedule.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskRecurringSchedule.groovy	(revision 875)
@@ -0,0 +1,108 @@
+import org.codehaus.groovy.runtime.TimeCategory
+// the above will be deprecated and replaced by: groovy.time.TimeCategory
+
+class TaskRecurringSchedule {
+
+    Task lastGeneratedSubTask
+    Period recurPeriod
+    Period taskDurationPeriod
+
+    Integer recurEvery = 1
+    Integer taskDuration = 0
+    Integer generateAhead = 1
+    Integer subTasksGenerated = 0
+    Integer maxSubTasks = 0
+    Date nextGenerationDate = new Date()
+    Date nextTargetStartDate = new Date()+1
+    Date nextTargetCompletionDate = new Date()
+    boolean enabled = true
+    boolean useTargetCompletionDate = false
+
+//     static hasMany = []
+
+    static belongsTo = [task: Task]
+
+    static constraints = {
+        recurEvery(min:1, max:365)
+        taskDuration(min:0, max:365)
+        generateAhead(min:0, max:62)
+        lastGeneratedSubTask(nullable:true)
+    }
+
+    String toString() {
+        "Recur every ${recurEvery} ${recurPeriod}"
+    }
+
+    // Events do not fire/pass before validation, since they are called during flushing.
+    // Defaults set above to pass validation.
+    def beforeInsert = {
+        setNextGenerationDate()
+        setNextTargetCompletionDate()
+    }
+
+    public void setNextTargetStartDate() {
+        switch (recurPeriod.period) {
+            case "Day(s)":
+                use(TimeCategory) {
+                    nextTargetStartDate = nextTargetStartDate + recurEvery.days
+                }
+                break
+            case "Week(s)":
+                use(TimeCategory) {
+                    nextTargetStartDate = nextTargetStartDate + recurEvery.weeks
+                }
+                break
+            case "Month(s)":
+                use(TimeCategory) {
+                    nextTargetStartDate = nextTargetStartDate + recurEvery.months
+                }
+                break
+            case "Year(s)":
+                use(TimeCategory) {
+                    nextTargetStartDate = nextTargetStartDate + recurEvery.years
+                }
+                break
+        default:
+                log.error "No case for recurPeriod.period: ${recurPeriod.period}"
+                break
+        }
+    }
+
+    public void setNextGenerationDate() {
+        use(TimeCategory) {
+            nextGenerationDate = nextTargetStartDate - generateAhead.days
+        }
+        def now = new Date()
+        if( nextGenerationDate < now) {nextGenerationDate = now}
+    }
+
+    public void setNextTargetCompletionDate() {
+        switch (taskDurationPeriod.period) {
+            case "Day(s)":
+                use(TimeCategory) {
+                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.days
+                }
+                break
+            case "Week(s)":
+                use(TimeCategory) {
+                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.weeks
+                }
+                break
+            case "Month(s)":
+                use(TimeCategory) {
+                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.months
+                }
+                break
+            case "Year(s)":
+                use(TimeCategory) {
+                    nextTargetCompletionDate = nextTargetStartDate + taskDuration.years
+                }
+                break
+            default:
+                log.error "No case for taskDurationPeriod.period: ${taskDurationPeriod.period}"
+                break
+        }
+    }
+
+}
+
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskStatus.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskStatus.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskStatus.groovy	(revision 875)
@@ -0,0 +1,14 @@
+class TaskStatus {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [tasks : Task]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {"${this.name}"}
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/TaskType.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/TaskType.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/TaskType.groovy	(revision 875)
@@ -0,0 +1,14 @@
+class TaskType {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [tasks : Task]
+
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {"${this.name}"}
+}
Index: /branches/features/grailsUpgrade/grails-app/domain/UnitOfMeasure.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/domain/UnitOfMeasure.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/domain/UnitOfMeasure.groovy	(revision 875)
@@ -0,0 +1,16 @@
+class UnitOfMeasure {
+    String name
+    String description = ""
+    boolean isActive = true
+
+    static hasMany = [inventoryItems: InventoryItem]
+    
+    static constraints = {
+        name(maxSize:50,unique:true,blank:false)
+        description(maxSize:100)
+    }
+
+    String toString() {
+        "${this.name}"
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/i18n/jasper.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/jasper.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/jasper.properties	(revision 875)
@@ -0,0 +1,4 @@
+jasper.controller.invalidFormat = Invalid format: {0}
+
+jasper.taglib.missingAttribute = Missing required attribute: {0}.  All of the following attributes are required: {1}.
+jasper.taglib.invalidFormatAttribute = Value {0} is an invalid format attribute.  Only {1} are permitted.
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages.properties	(revision 875)
@@ -0,0 +1,535 @@
+#
+# Custom and domain constraint messages.
+#
+
+address.owner.not.found=An owner (Person, Site or Supplier) must be supplied to create an address.
+contact.owner.not.found=An owner (Person, Site or Supplier) must be supplied to create contact details.
+
+asset.tree.import.success=Asset tree imported.
+asset.tree.import.failure=Could not create asset tree from supplied file, failed on line {0}, see {1}.
+
+inventory.import.success=Inventory imported.
+inventory.import.failure=Could not create inventory from supplied file, failed on line {0}, see {1}.
+
+inventoryItemPictures.import.success=Inventory item pictures imported, see {0}.
+inventoryItemPictures.import.failure.no.directory=Import directory on server not found.
+inventoryItemPictures.import.failure.to.unzip=Failed to unzip supplied file.
+inventoryItemPictures.import=Picture Import
+inventoryItemPictures.import.help=A zip file of pictures (max 100MB) or singles pictures may be imported. Pictures \
+    must have the same file names as existing inventory items.
+
+inventoryItemPurchase.import.success=Inventory item purchases imported.
+inventoryItemPurchase.import.failure=Could not create inventory item purchases from supplied file, failed on line {0}, see {1}.
+
+person.import.success=Person list imported.
+person.import.failure=Could not create persons from supplied file, failed on line {0}, see {1}.
+
+asset.copy.subItem.create.failure=Could not complete operation, as sub item failed to save.
+asset.copy.subItem.too.many.failure=Could not complete operation, as there appears to be too many sub items.
+asset.copy.method.required=Please select a copy method for sub items.
+asset.copy.method=Copy Method
+asset.copy.method.help=Link creates a new asset and links it to EXISTING sub items. \
+    While copy creates a new asset and new sub items by appending '(id:#)' to create unique sub item names.
+asset.copy.asset.required=Please select an asset to copy.
+
+maintenanceActions.still.associated=Could not complete operation as maintenance actions are still associated \
+    with this item.
+maintenanceActions.still.associated.subItem=Could not complete operation as maintenance actions are still associated \
+    with a sub item.
+inventoryStores.still.associated=Could not complete operation as inventory stores are still associated with this item.
+
+site.section.delete.failure=Could not complete operation as sections failed to delete.
+section.asset.delete.failure=Could not complete operation as assets failed to delete.
+asset.subItems.delete.failure=Could not complete operation as orphan sub items failed to delete.
+
+assetSubItem.asset.not.found=Could not complete operation as an asset was supplied but not found.
+assetSubItem.assets.associated=Could not complete operation as assets are still associated with this sub item.
+
+sub.task.create.confirm=Immediately create and save a new sub task?
+
+person.pass.minSize.notmet=Password is less than the minimum size of [{3}]
+person.pass.blank=Password cannot be blank
+person.pass.doesNotMatch=Passwords must match
+
+costCode.name.not.unique.for.purchasing.group=CostCode name must be unique for purchasingGroup.
+
+#
+# Help Balloon and property definitions.
+#
+
+# Report help balloon messages.
+report.stock.take.overview=Stock Take (Overview)
+report.stock.take.overview.help=Use this report to manage inventory stock take. Use in conjunction with the Stock Take (By Location) report.
+report.stock.take.by.location=Stock Take (Location)
+report.stock.take.by.location.help=Enter a comma separated list of inventory locations. \
+    Use the Stock Take (Overview) report to get the list of locations. A % symbol may be used as a wild card, e.g: X1, X2, Y%, Z%7
+
+# Person properties.
+person.personGroups=Person Groups
+person.personGroups.help=Groups may be assigned to tasks and \
+may also provide a record of persons qualified or trained in a specific area. \
+    Groups provide no application authorisations.
+person.purchasingGroups=Purchasing Groups
+person.purchasingGroups.help=Purchasing groups determine the available cost codes that a person may purchase against.
+person.loginName=Login Name
+person.loginName.help=This is the id or name that the person will use to login to the application.
+person.firstName=First Name
+person.firstName.help=The person's real first name.
+person.lastName=Last Name
+person.lastName.help=The person's real last name.
+person.password=Password
+person.password.help=The password that the person will use to login to the application (should be changed by them later).
+person.isActive=Active
+person.isActive.help=Disable this to prevent a person logging in to the application.
+
+person.authorities=Authorities
+person.authorities.help=Give this person authority to do things in the application. \
+    The user must logout for changes to take effect.
+
+# InventoryItemPurchase properties.
+inventoryItemPurchase.purchaseOrderNumber=Purchase Order #
+inventoryItemPurchase.purchaseOrderNumber.help=This number must be exact in case and spacing. \
+    All purchase received and invoice approval requires this number to track correctly. \
+    The number may only appear once for each inventory item. \
+    To enter multiple line items for a purchase order # 'M123' use 'M123.1' and 'M123.2' for example.
+inventoryItemPurchase.order.placed.date=Date
+inventoryItemPurchase.order.placed.date.help=The date that the order was placed. \
+    May be adjusted at the end of financial years. Also see the 'date created' and 'last updated' properties.
+inventoryItemPurchase.cost.code=Cost Code
+inventoryItemPurchase.cost.code.help=Cost codes assign cost to the correct asset and accouting ledger number/account. \
+    Ideally cost codes should be asset based and reflect the asset tree.
+inventoryItemPurchase.task.budget.status=Budget Status
+inventoryItemPurchase.task.budget.status.help=Was this purchase planned for in the budget or is it an unplanned spend.
+inventoryItemPurchase.supplier=Supplier
+inventoryItemPurchase.supplier.help=The supplier to make the purchase out to.
+inventoryItemPurchase.quantity=Quantity
+inventoryItemPurchase.quantity.help=The number of inventory item units purchased.
+inventoryItemPurchase.receive.quantity=Receive Quantity
+inventoryItemPurchase.receive.quantity.help=The number of inventory item units received.
+inventoryItemPurchase.approve.quantity=Approve Quantity
+inventoryItemPurchase.approve.quantity.help=The number of inventory item units to approve payment for.
+inventoryItemPurchase.order.value=Order Value
+inventoryItemPurchase.order.value.help=The total value of this line item.
+inventoryItemPurchase.receive.value=Receive Value
+inventoryItemPurchase.receive.value.help=The value of items received.
+inventoryItemPurchase.approve.value=Approve Value
+inventoryItemPurchase.approve.value.help=The value to approve payment for.
+inventoryItemPurchase.invoice.number=Invoice Number
+inventoryItemPurchase.invoice.number.help=The invoice number that this line item approves payment for.
+
+entry.duration=Duration
+entry.duration.help=The time (hh:mm) booked against this entry for date done.
+entry.duration.fault=Down Time.
+entry.duration.fault.help=The production down time (hh:mm) directly attributable to this fault.
+entry.date.done=Date Done
+entry.date.done.help=The date on which the event actually occurred.
+entry.comment.fault=Fault
+entry.comment.fault.help=Techinical description of the fault and what is happening, NOT what needs doing!
+entry.comment.cause=Cause
+entry.comment.cause.help=The root cause of the fault. Professional opinion on any faults. \
+Include condition and contributing factors.
+entry.comment.work.done=Work Done
+entry.comment.work.done.help=Describe the work that was done.
+entry.comment.production.note=Production Note
+entry.comment.production.note.help=Comment on the production.
+entry.comment.work.request=Work Request
+entry.comment.work.request.help=Describe the work request.
+entry.comment.pm.entry=PM Entry
+entry.comment.pm.entry.help=Describe the condition severity and work done. \
+    Steps may be grouped by severity but all steps must have an entry.
+entry.productionReference.fault=Production Reference
+entry.productionReference.fault.help=The production during which the fault occurred.
+
+assignedGroup.estimatedDuration=Estimated Duration
+assignedGroup.estimatedDuration.help=The estimated amount of time (hh:mm) that you would \
+like to assign this group to the task.
+
+assignedPerson.estimatedDuration=Estimated Duration
+assignedPerson.estimatedDuration.help=The estimated amount of time (hh:mm) that you would \
+like to assign this person to the task.
+
+task.delete.failure.production=Tasks may not be deleted in production mode, \
+    set the trash flag instead.
+task.trash.confirm=Trash, are you sure? \
+    If authorised, recurrence will be disabled and Sub Task links will be forever removed!
+task.clear.attention.flag.on.completion.confirm=Clear Flag and Complete, are you sure?
+task.notFound=Could not complete operation, task not found.
+task.operationNotPermittedOnCompleteTask=This operation is not permitted on a complete task.
+task.operationNotPermittedOnTaskInTrash=This operation is not permitted on a task that is in the trash.
+task.operationNotPermittedOnRecurringTask=This operation is not permitted \
+    on a recurring task, please see the Sub Tasks.
+task.operationNotPermittedOnRecurringTaskWithoutAuth=This operation is not permitted \
+    on a recurring task without authorisation.
+task.operationNotPermittedOnTaskHavingSubTasksWithoutAuth=This operation is not permitted \
+    on a task that has sub tasks without authorisation.
+task.operationNotPermittedOnTaskLinkedToProcedureWithoutAuth=This operation is not permitted \
+    on a task that is linked to a procedure without authorisation.
+task.operationNotPermittedOnParentPmTask=This operation is not permitted \
+    on a Parent PM task.
+task.createEntryNotPermittedOnTaskWithProcedure=This operation is not permitted \
+    on a task with a procedure, please create entries on the procedure tab.
+task.failedToSave=Could not complete operation, task failed to save.
+task.modifications.failedToSave=Could not complete operation, as task modification record failed to save.
+task.assignedGroups.failedToSave=Could not complete operation, as assignedGroup record failed to save.
+task.assignedPersons.failedToSave=Could not complete operation, as assignedPerson record failed to save.
+tast.taskRecurringSchedule.alreadyExists=This task already has a recurring schedule.
+tast.operationNotPermittedToChangeAssetWithMaintenanceActions=Changing the primaryAsset \
+    on a task with maintenanceActions is not permitted, remove the maintenanceActions from the \
+    procedure first.
+task.targetCompletionDate.before.targetStartDate=The target completion date must be equal to or greater than \
+    the target start date.
+
+entry.highestSeverity.not.nullable.for.pm.entry=Please select a condition severity.
+entry.create.no.params=Please select a task, then add an entry.
+entry.create.no.params.ajax=Incorrect params supplied.
+
+taskRecurringSchedule.notFound=Could not complete operation, recurring schedule not found.
+personGroup.not.found=Person Group not found, it may have been deleted.
+person.not.found=Person record not found, it may have been deleted.
+
+# Task Properties.
+task.assignedGroups=Assigned Groups
+task.assignedGroups.help=The person groups assigned to work on this task during planning along with estimated time.
+task.assignedPersons=Assigned Persons
+task.assignedPersons.help=The persons assigned to work on this task during planning along with estimated time.
+task.description=Task Description
+task.description.help=Short basic description of the task.
+task.description.immediateCallout=Immediate Callout Description.
+task.description.immediateCallout.help=Short description of the callout from an operations perspective.
+task.comment=Task Comment
+task.comment.help=Long text for additional info, only shown in detail views.
+task.targetStartDate=Target Start Date
+task.targetStartDate.help=The date we would like the task to start, set during scheduling.
+task.targetStartDate.immediateCallout=Callout Date
+task.targetStartDate.immediateCallout.help=The date the callout occured.
+task.targetCompletionDate=Target Completion Date
+task.targetCompletionDate.help=The date we would like the task to be completed by, set during scheduling.
+task.leadPerson=Lead Person
+task.leadPerson.help=The primay contact person.
+task.safetyRequirement=Safety
+task.safetyRequirement.help=Completion of this task is required to correct an immediate safety concern. \
+    This task must be completed and is not allowed to be missed.
+task.regulatoryRequirement=Regulatory
+task.regulatoryRequirement.help=Completion of this task is a regulatory requirement. \
+    This task must be completed and is not allowed to be missed.
+task.mandatoryRequirement=Mandatory
+task.mandatoryRequirement.help=Completion of this task is mandatory, due to company policy or operational requirement. \
+    This task must be completed and is not allowed to be missed.
+task.positiveFault=Positive Fault
+task.positiveFault.help=Set false if unsure. Used to calculate preventative efficiency or P.E.
+
+# Task Actions
+task.status.resolved=Resolved
+task.status.resolved.help=Indicate that root cause is known and has been completely resolved.
+task.status.unresolved=Unresolved
+task.status.unresolved.help=Indicate that this task requires further attention, \
+    root cause is either unknown or unresolved.
+task.status.resolved.save.entry=Resolved
+task.status.resolved.save.entry.help=Save entry and complete task.
+task.status.unresolved.save.entry=Unresolved
+task.status.unresolved.save.entry.help=Save entry and indicate that this task requires further attention, \
+    root cause is either unknown or unresolved.
+task.save.entry=Save
+task.save.entry.help=Save entry and leave task status unchanged.
+
+taskRecurringSchedule.nextTargetStartDate.mayNotBePast=Please select a start date that is not in the past.
+taskRecurringSchedule.nextTargetStartDate=Next Target Start Date
+taskRecurringSchedule.nextTargetStartDate.help=The target start date for the next auto generated sub task.
+taskRecurringSchedule.recurEvery=Recur Every
+taskRecurringSchedule.recurEvery.help=How often this task should recur. Determines the period between sub task target start dates.
+taskRecurringSchedule.taskDuration=Task Duration
+taskRecurringSchedule.taskDuration.help=How long to allow for the task. Determines the target completion date of the sub tasks.
+taskRecurringSchedule.generateAhead=Generate Ahead
+taskRecurringSchedule.generateAhead.help=How far ahead of the next target start date to generate sub tasks. \
+    This allows work packs to be built and work load to be seen and planned. \
+    Only generate ahead as far as short term planning is done, since all generated sub task \
+    values will be set and therefore time consuming to change.
+taskRecurringSchedule.maxSubTasks=Max Sub Tasks
+taskRecurringSchedule.maxSubTasks.help=Maximum number of sub tasks to generate. Set to 0 \
+    for no limit.
+taskRecurringSchedule.useTargetCompletionDate=Target Completion
+taskRecurringSchedule.useTargetCompletionDate.help=On to use the parent task's target completion date. \
+    Off to continue generation past the parent task's target completion date.
+taskRecurringSchedule.enabled=Enabled
+taskRecurringSchedule.enabled.help=On to enable automatic sub task generation. \
+    Off to stop automatic sub task generation. <br /><br />\
+    The system will turn this off if there are no further sub tasks to be generated.
+
+task.primaryAsset=Primary Asset
+task.primaryAsset.help=This is the asset that costs will be assigned to.
+task.associatedAssets=Associated Assets
+task.associatedAssets.help=These assets are to be associated with this task, but costs will not be assigned.
+
+# InventoryItem Properties.
+inventory.item.name=Name
+inventory.item.name.help=The inventory item's name as known on site. \
+    Also called the part number but may contain letters and numbers.
+inventory.item.description=Description
+inventory.item.description.help=The inventory item description as it would appear on a reorder.
+inventory.item.comment=Comment
+inventory.item.comment.help=Additional on site comments. Which may include additional ordering information, \
+    search key words and other useful information.
+inventory.item.estimated.unit.price.amount=Unit Price
+inventory.item.estimated.unit.price.amount.help=Estimated reorder price of a single unit.
+inventory.item.unit.of.measure=Unit Of Measure
+inventory.item.unit.of.measure.help=The units that this item will be measured in. Set once during creation \
+    and cannot be changed as changing would invalidate all movement, another item with the correct units must be created.
+inventory.item.suppliers.part.number=Part Number
+inventory.item.suppliers.part.number.help=The suppliers part number as it would appear on a reorder.
+inventory.item.units.in.stock=In Stock
+inventory.item.units.in.stock.help=Current units in stock.
+inventory.item.reorder.point=Reorder Point
+inventory.item.reorder.point.help=Point at which a reorder will be flagged.
+inventory.item.reorder.quantity=Reorder Quantity
+inventory.item.reorder.quantity.help=Typical or recommended quantity to reorder. \
+    Infers the max holding quantity (Reorder Point + Reorder Quantity). \
+    Often determined by a price break or minimum order quantity.
+inventory.item.is.active=Active
+inventory.item.is.active.help=Disable to remove from search results.
+inventory.item.is.obsolete=Obsolete
+inventory.item.is.obsolete.help=Enabled indicates that item considered obsolete by the supplier.
+inventory.item.enable.reorder.listing=Reorder Listing
+inventory.item.enable.reorder.listing.help=Enabled to show item on reorder lists.
+inventory.item.inventory.location=Location
+inventory.item.inventory.location.help=The location or bin where this item can be found.
+inventory.item.inventory.group=Group
+inventory.item.inventory.group.help=An easy way to group or place items in various piles to assit with management.
+inventory.item.inventory.type=Type
+inventory.item.inventory.type.help=The type of inventory that this item falls into.
+inventory.item.preferred.supplier=Preferred Supplier
+inventory.item.preferred.supplier.help=The preferred supplier to purchase this item from. \
+    Often determined by cost, contract or availability.
+inventory.item.alternate.suppliers=Alternate Suppliers
+inventory.item.alternate.suppliers.help=List of alternate suppliers that this item may be purchased from. \
+    For example when the preferred supplier has no stock.
+inventory.item.spare.for=Spare For
+inventory.item.spare.for.help=List of assets that this item is held as a spare for.
+
+# InventoryItem Messages.
+inventory.item.is.obsolete.message=This item has been flagged as obsolete.
+inventory.item.not.active.message=This item has been flagged as not active.
+inventory.item.reorder.not.allowed=Reorder not allowed.
+inventory.item.reorder.listing.disabled=This item has reorder listing disabled and will not appear on reorder lists.
+inventory.item.already.has.picture=Inventory item already has a picture, please delete the old picture first.
+inventory.item.picture.file.unrecognised=Image file [{0}]: type not recognised.
+inventory.item.picture.source.not.supported=Image source type not supported.
+
+inventoryMovement.quantity.insufficientItemsInStock=Could not complete operation, insufficient items in stock.
+inventoryMovement.inventoryItem.notFound=Inventory Item not found.
+inventoryMovement.still.associated=Could not complete operation as inventory movements are still associated with this item.
+
+inventoryItemPurchase.purchaseOrderNumber.not.unique.for.inventory.item.order=Purchase Order Number must be unique for this inventory item order.
+inventoryItemPurchase.invoiceNumber.required=An invoice number must be supplied to approve payment.
+inventoryItemPurchase.delete.failure.received.exists=Could not delete, items have been received.
+inventoryItemPurchase.delete.failure.payment.approved=Could not delete, payment has been approved.
+inventoryItemPurchase.operation.not.permitted.on.inactive.or.obsolete.item=This operation is not permitted on an inactive or obsolete inventory item.
+inventoryItemPurchase.costCodes.not.found=No cost codes found, a person needs to be assigned to a purchasing group that has cost codes.
+
+assignedGroup.task.not.found=Please select a task and then ''Add Assigned Group''.
+assignedPerson.task.not.found=Please select a task and then ''Add Assigned Person''.
+
+#
+# Default messages.
+#
+
+default.list.failure=Could not generate list for class {0}.
+default.not.found={0} {1} not found, it may have been deleted.
+default.delete.success={0} {1} deleted.
+default.delete.failure={0} {1} could not be deleted.
+default.update.success={0} {1} updated.
+default.update.failure={0} {1} could not be updated.
+default.create.success={0} {1} created.
+default.create.failure={0} could not be created.
+default.create.revision.failure=Could not create revision.
+default.could.not.perform.operation=Could not perform operation.
+default.optimistic.locking.failure=Another user has updated this item while you were editing, please check the updated values.
+default.file.over.max.size=Supplied file is greater than max size of {0} {1}.
+default.file.not.supplied=No file supplied.
+default.file.no.header=The supplied file does not have the correct header lines, please see the template file.
+default.not.development.environment.failure=Could not complete operation, dev environment not detected.
+
+default.doesnt.match.message=Property [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}]
+default.invalid.url.message=Property [{0}] of class [{1}] with value [{2}] is not a valid URL
+default.invalid.creditCard.message=Property [{0}] of class [{1}] with value [{2}] is not a valid credit card number
+default.invalid.email.message=Property [{0}] of class [{1}] with value [{2}] is not a valid e-mail address
+default.invalid.range.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}]
+default.invalid.size.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
+default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
+default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
+default.invalid.max.size.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
+default.invalid.min.size.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}]
+default.invalid.validator.message=Property [{0}] of class [{1}] with value [{2}] does not pass custom validation
+default.not.inlist.message=Property [{0}] of class [{1}] with value [{2}] is not contained within the list [{3}]
+default.blank.message=Property [{0}] of class [{1}] cannot be blank
+default.not.equal.message=Property [{0}] of class [{1}] with value [{2}] cannot equal [{3}]
+default.null.message=Property [{0}] of class [{1}] cannot be null
+default.not.unique.message=Property [{0}] of class [{1}] with value [{2}] must be unique
+
+default.paginate.prev=Previous
+default.paginate.prev.abbrev=Prev
+default.paginate.next=Next
+
+default.close.text=Close
+default.options.text=Options
+default.none.text=None
+default.all.text=All
+default.please.select.text=--Please-Select--
+default.none.select.text=--None--
+default.all.select.text=--All--
+
+#
+# Rich UI plugin - Calendar
+#
+
+default.time=Time
+default.week=Week
+default.monday=Mon
+default.tuesday=Tues
+default.wednesday=Wed
+default.thursday=Thu
+default.friday=Fri
+default.saturday=Sat
+default.sunday=Sun
+
+#
+# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
+#
+
+typeMismatch.java.net.URL=Property {0} must be a valid URL
+typeMismatch.java.net.URI=Property {0} must be a valid URI
+typeMismatch.java.util.Date=Property {0} must be a valid Date
+typeMismatch.java.lang.Double=Property {0} must be a valid number
+typeMismatch.java.lang.Integer=Property {0} must be a valid number
+typeMismatch.java.lang.Long=Property {0} must be a valid number
+typeMismatch.java.lang.Short=Property {0} must be a valid number
+typeMismatch.java.math.BigDecimal=Property {0} must be a valid number
+typeMismatch.java.math.BigInteger=Property {0} must be a valid number
+
+#
+# Navigation plugin, see conf/Config.groovy for menu's.
+# Subitems are not currently resolving with this plugin.
+#
+
+navigation.nav.home=Home
+navigation.nav.home.start=Start
+navigation.nav.home.appAdmin=Admin
+navigation.nav.home.manager=Manager
+navigation.nav.home.changeSessionTimeout=Timeout
+navigation.nav.home.changePassword=Password
+
+navigation.nav.tasks=Tasks
+navigation.nav.tasks.create=Create
+navigation.nav.tasks.search=Search
+navigation.nav.tasks.show=Show
+
+navigation.nav.inventory=Inventory
+navigation.nav.assets=Assets
+
+#
+# FilterPane plugin, properties.
+#
+
+fp.property.text.associatedAssets.name=Associated Asset
+fp.property.text.primaryAsset.name=Primary Asset
+fp.property.text.trash=Trash
+fp.property.text.scheduled=Scheduled
+fp.property.text.approved=Approved
+fp.property.text.isObsolete=Obsolete
+fp.property.text.taskGroup.name=Group
+fp.property.text.taskPriority.name=Priority
+fp.property.text.taskStatus.name=Status
+fp.property.text.description=Description
+fp.property.text.comment=Comment
+fp.property.text.leadPerson.lastName=Lead Person (Last Name)
+fp.property.text.leadPerson.firstName=Lead Person (First Name)
+fp.property.text.taskType.name=Type
+fp.property.text.inventoryLocation.name=Location
+fp.property.text.spareFor.name=Spare For
+fp.property.text.supplier.name=Supplier
+fp.property.text.estimatedUnitPriceAmount=Estimated Unit Price
+
+fp.property.text.inventoryItemPurchaseType.name=Type
+
+#
+# TaskSearch Service.
+#
+
+task.search.include.completed=Incl. Completed
+task.search.include.completed.help=Include completed tasks in the results.
+
+task.search.text.all.tasks=All Tasks
+task.search.text.all.tasks.help=All tasks that are not in the trash. Tasks in the trash must be explicitly requested in the advanced search.
+task.search.text.all.tasks.message=All tasks for {0}.
+task.search.text.all.tasks.none.found=No tasks found for {0}.
+task.search.text.all.tasks.between.message=All tasks between {0} and {1}.
+task.search.text.all.tasks.between.none.found=No tasks found between {0} and {1}.
+
+task.search.text.persons.tasks=Person's Tasks
+task.search.text.persons.tasks.help=Approved tasks that a person is assigned to.
+task.search.text.persons.tasks.message=Tasks for {0} on {1}.
+task.search.text.persons.tasks.none.found=No tasks found for {0} on {1}.
+task.search.text.persons.tasks.between.message=Tasks for {0} between {1} and {2}.
+task.search.text.persons.tasks.between.none.found=No tasks found for {0} between {1} and {2}.
+
+task.search.text.my.todays=Today
+task.search.text.my.todays.description=My tasks and approved tasks that I am assigned to.
+
+task.search.text.persons.immediate.callouts=Person's Callouts
+task.search.text.persons.immediate.callouts.help=Immediate callouts by person (lead person or created by).
+task.search.text.persons.immediate.callouts.message=Immediate callouts for {0} on {1}.
+task.search.text.persons.immediate.callouts.none.found=No immediate callouts found for {0} on {1}.
+task.search.text.persons.immediate.callouts.between.message=Immediate callouts for {0} between {1} and {2}.
+task.search.text.persons.immediate.callouts.between.none.found=No immediate callouts found for {0} between {1} and {2}.
+
+task.search.calendar.text.too.many.results=Too many results, only {0} are shown.
+task.search.text.work.done=Work Done
+task.search.text.work.done.description=Work done by person and date.
+task.search.text.work.done.message=Work done by {0} on {1}.
+task.search.text.work.done.none.found=No entries found for {0} on {1}.
+task.search.text.work.load=Work Load
+task.search.text.work.load.description=Work load by group and date.
+task.search.text.work.load.message=Work load between {0} and {1}.
+task.search.text.work.load.none.found=No tasks found between {0} and {1}.
+task.search.text.work.load.too.many.results=Too many tasks found to perform calculatation, {0} / {1} shown.
+
+#
+# InventoryItemSearch
+#
+
+inventoryItem.search.searchText=Search
+inventoryItem.search.searchText.help=By default all words are matched and results are sorted by relevance. \
+    A * symbol may be used as a wild card, e.g: '2305*' would find 2305RS and 2305-RS. A + symbol may be used to require a word \
+    e.g: 'sensor +print' would require results to have 'print' in the searched categories.
+inventoryItem.search.text.found=Results for: {0}
+inventoryItem.search.text.none.found=No results for: {0}
+inventoryItem.search.text.below.reorder=Below Reorder
+inventoryItem.search.text.below.reorder.description=Inventory items at or below reorder point.
+inventoryItem.search.text.below.reorder.all=Below Reorder (all)
+inventoryItem.search.text.below.reorder.all.description=Inventory items at or below reorder point, including reorder listing disabled.
+inventoryItem.search.text.below.reorder.none.found=No inventory items found at or below reorder point.
+inventoryItem.search.text.all.description=All inventory items.
+inventoryItem.search.text.all.none.found=No inventory items found.
+inventoryItem.search.text.recently.used=Recently Used
+inventoryItem.search.text.recently.used.description=Items used in the last {0} days.
+inventoryItem.search.text.recently.used.none.found=No items used in the last {0} days.
+
+#
+# Report error messages.
+#
+
+report.error.too.many.results=Error: over {0} results, please run report again.
+report.error.no.locations.found=Error: no locations found, please run report again.
+report.error.too.many.locations=Error: over {0} locations, please run report again.
+report.error.no.inventory.items.found=Error: no inventory items found, please run report again.
+report.error.too.many.inventory.items=Error: over {0} inventory items, please run report again.
+report.error.multiple.currency.found=Error: multiple currency found.
+
+#
+# AppCore messages.
+#
+appCore.rebuild.text.search.index=The text search index is being rebuilt in the background, see log file for details.
+
+#
+# Ajax messages.
+#
+ajax.default.could.not.perform.operation=Could not perform operation, is the connection ok?
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_de.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_de.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_de.properties	(revision 875)
@@ -0,0 +1,30 @@
+default.doesnt.match.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] entspricht nicht dem vorgegebenen Muster [{3}]
+default.invalid.url.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gÃŒltige URL
+default.invalid.creditCard.message=Das Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gÃŒltige Kreditkartennummer
+default.invalid.email.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist keine gÃŒltige E-Mail Adresse
+default.invalid.range.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht im Wertebereich von [{3}] bis [{4}]
+default.invalid.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht im Wertebereich von [{3}] bis [{4}]
+default.invalid.max.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist grÃ¶Ãer als der HÃ¶chstwert von [{3}]
+default.invalid.min.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist kleiner als der Mindestwert von [{3}]
+default.invalid.max.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ÃŒbersteigt den HÃ¶chstwert von [{3}]
+default.invalid.min.size.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] unterschreitet den Mindestwert von [{3}]
+default.invalid.validator.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist ungÃŒltig
+default.not.inlist.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] ist nicht in der Liste [{3}] enthalten.
+default.blank.message=Die Eigenschaft [{0}] des Typs [{1}] darf nicht leer sein
+default.not.equal.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] darf nicht gleich [{3}] sein
+default.null.message=Die Eigenschaft [{0}] des Typs [{1}] darf nicht null sein
+default.not.unique.message=Die Eigenschaft [{0}] des Typs [{1}] mit dem Wert [{2}] darf nur einmal vorkommen
+
+default.paginate.prev=Vorherige
+default.paginate.next=NÃ€chste
+
+# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
+typeMismatch.java.net.URL=Die Eigenschaft {0} muss eine gÃŒltige URL sein
+typeMismatch.java.net.URI=Die Eigenschaft {0} muss eine gÃŒltige URI sein
+typeMismatch.java.util.Date=Die Eigenschaft {0} muss ein gÃŒltiges Datum sein
+typeMismatch.java.lang.Double=Die Eigenschaft {0} muss eine gÃŒltige Zahl sein
+typeMismatch.java.lang.Integer=Die Eigenschaft {0} muss eine gÃŒltige Zahl sein
+typeMismatch.java.lang.Long=Die Eigenschaft {0} muss eine gÃŒltige Zahl sein
+typeMismatch.java.lang.Short=Die Eigenschaft {0} muss eine gÃŒltige Zahl sein
+typeMismatch.java.math.BigDecimal=Die Eigenschaft {0} muss eine gÃŒltige Zahl sein
+typeMismatch.java.math.BigInteger=Die Eigenschaft {0} muss eine gÃŒltige Zahl sein
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_es.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_es.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_es.properties	(revision 875)
@@ -0,0 +1,30 @@
+default.doesnt.match.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no corresponde al patrÃ³n [{3}]
+default.invalid.url.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es una URL vÃ¡lida
+default.invalid.creditCard.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es un nÃºmero de tarjeta de crÃ©dito vÃ¡lida
+default.invalid.email.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es una direcciÃ³n de correo electrÃ³nico vÃ¡lida
+default.invalid.range.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no entra en el rango vÃ¡lido de [{3}] a [{4}]
+default.invalid.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no entra en el tamaÃ±o vÃ¡lido de [{3}] a [{4}]
+default.invalid.max.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] excede el valor mÃ¡ximo [{3}]
+default.invalid.min.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] es menos que el valor mÃ­nimo [{3}]
+default.invalid.max.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] excede el tamaÃ±o mÃ¡ximo de [{3}]
+default.invalid.min.size.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] es menor que el tamaÃ±o mÃ­nimo de [{3}]
+default.invalid.validator.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no es vÃ¡lido
+default.not.inlist.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no esta contenido dentro de la lista [{3}]
+default.blank.message=La propiedad [{0}] de la clase [{1}] no puede ser vacÃ­a
+default.not.equal.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] no puede igualar a [{3}]
+default.null.message=La propiedad [{0}] de la clase [{1}] no puede ser nulo
+default.not.unique.message=La propiedad [{0}] de la clase [{1}] con valor [{2}] debe ser Ãºnica
+
+default.paginate.prev=Anterior
+default.paginate.next=Siguiente
+
+# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
+typeMismatch.java.net.URL=La propiedad {0} debe ser una URL vÃ¡lida
+typeMismatch.java.net.URI=La propiedad {0} debe ser una URI vÃ¡lida
+typeMismatch.java.util.Date=La propiedad {0} debe ser una fecha vÃ¡lida
+typeMismatch.java.lang.Double=La propiedad {0} debe ser un nÃºmero vÃ¡lido
+typeMismatch.java.lang.Integer=La propiedad {0} debe ser un nÃºmero vÃ¡lido
+typeMismatch.java.lang.Long=La propiedad {0} debe ser un nÃºmero vÃ¡lido
+typeMismatch.java.lang.Short=La propiedad {0} debe ser un nÃºmero vÃ¡lido
+typeMismatch.java.math.BigDecimal=La propiedad {0} debe ser un nÃºmero vÃ¡lido
+typeMismatch.java.math.BigInteger=La propiedad {0} debe ser un nÃºmero vÃ¡lido
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_fr.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_fr.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_fr.properties	(revision 875)
@@ -0,0 +1,19 @@
+default.doesnt.match.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] ne correspond pas au pattern [{3}]
+default.invalid.url.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas une URL valide
+default.invalid.creditCard.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas un numÃ©ro de carte de crÃ©dit valide
+default.invalid.email.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas une adresse e-mail valide
+default.invalid.range.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas contenue dans l'intervalle [{3}] Ã  [{4}]
+default.invalid.size.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas contenue dans l'intervalle [{3}] Ã  [{4}]
+default.invalid.max.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] est supÃ©rieure Ã  la valeur maximum [{3}]
+default.invalid.min.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] est infÃ©rieure Ã  la valeur minimum [{3}]
+default.invalid.max.size.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] est supÃ©rieure Ã  la valeur maximum [{3}]
+default.invalid.min.size.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] est infÃ©rieure Ã  la valeur minimum [{3}]
+default.invalid.validator.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] n'est pas valide
+default.not.inlist.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] ne fait pas partie de la liste [{3}]
+default.blank.message=La propriÃ©tÃ© [{0}] de la classe [{1}] ne peut pas Ãªtre vide
+default.not.equal.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] ne peut pas Ãªtre Ã©gale Ã  [{3}]
+default.null.message=La propriÃ©tÃ© [{0}] de la classe [{1}] ne peut pas Ãªtre nulle
+default.not.unique.message=La propriÃ©tÃ© [{0}] de la classe [{1}] avec la valeur [{2}] doit Ãªtre unique
+
+default.paginate.prev=PrÃ©cÃ©dent
+default.paginate.next=Suivant
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_it.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_it.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_it.properties	(revision 875)
@@ -0,0 +1,19 @@
+default.doesnt.match.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non corrisponde al pattern [{3}]
+default.invalid.url.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non Ãš un URL valido
+default.invalid.creditCard.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non Ãš un numero di carta di credito valido
+default.invalid.email.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non Ãš un indirizzo email valido
+default.invalid.range.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non rientra nell'intervallo valido da [{3}] a [{4}]
+default.invalid.size.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non rientra nell'intervallo di dimensioni valide da [{3}] a [{4}]
+default.invalid.max.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] Ãš maggiore di [{3}]
+default.invalid.min.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] Ãš minore di [{3}]
+default.invalid.max.size.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] Ãš maggiore di [{3}]
+default.invalid.min.size.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] Ãš minore di [{3}]
+default.invalid.validator.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non Ãš valida
+default.not.inlist.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non Ãš contenuta nella lista [{3}]
+default.blank.message=La proprietÃ  [{0}] della classe [{1}] non puÃ² essere vuota
+default.not.equal.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] non puÃ² essere uguale a [{3}]
+default.null.message=La proprietÃ  [{0}] della classe [{1}] non puÃ² essere null
+default.not.unique.message=La proprietÃ  [{0}] della classe [{1}] con valore [{2}] deve essere unica
+
+default.paginate.prev=Precedente
+default.paginate.next=Successivo
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_ja.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_ja.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_ja.properties	(revision 875)
@@ -0,0 +1,22 @@
+default.doesnt.match.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ã[{3}]ãã¿ãŒã³ãšäžèŽããŠããŸããã
+default.invalid.url.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãURLã§ã¯ãããŸããã
+default.invalid.creditCard.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãæ­£åœãªã¯ã¬ãžããã«ãŒãçªå·ã§ã¯ãããŸããã
+default.invalid.email.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãã¡ãŒã«ã¢ãã¬ã¹ã§ã¯ãããŸããã
+default.invalid.range.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ã[{3}]ãã[{4}]ç¯å²å
+ãæå®ããŠãã ããã
+default.invalid.size.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ã[{3}]ãã[{4}]ä»¥å
+ãæå®ããŠãã ããã
+default.invalid.max.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãæå€§å€[{3}]ããå€§ããã§ãã
+default.invalid.min.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãæå°å€[{3}]ããå°ããã§ãã
+default.invalid.max.size.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãæå€§å€[{3}]ããå€§ããã§ãã
+default.invalid.min.size.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãæå°å€[{3}]ããå°ããã§ãã
+default.invalid.validator.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ãã«ã¹ã¿ã ããªããŒã·ã§ã³ãééã§ããŸããã
+default.not.inlist.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ã[{3}]ãªã¹ãå
+ã«å­åšããŸããã
+default.blank.message=[{1}]ã¯ã©ã¹ã®ãã­ããã£[{0}]ã®ç©ºçœã¯èš±å¯ãããŸããã
+default.not.equal.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯ã[{3}]ãšåç­ã§ã¯ãããŸããã
+default.null.message=[{1}]ã¯ã©ã¹ã®ãã­ããã£[{0}]ã«nullã¯èš±å¯ãããŸããã
+default.not.unique.message=ã¯ã©ã¹[{1}]ãã­ããã£[{0}]ã®å€[{2}]ã¯æ¢ã«äœ¿çšãããŠããŸãã
+
+default.paginate.prev=æ»ã
+default.paginate.next=æ¬¡ãž
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_nl.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_nl.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_nl.properties	(revision 875)
@@ -0,0 +1,30 @@
+default.doesnt.match.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] komt niet overeen met het vereiste patroon [{3}]
+default.invalid.url.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldige URL
+default.invalid.creditCard.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldig credit card nummer
+default.invalid.email.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is geen geldig e-mailadres
+default.invalid.range.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] valt niet in de geldige waardenreeks van [{3}] tot [{4}]
+default.invalid.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] valt niet in de geldige grootte van [{3}] tot [{4}]
+default.invalid.max.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] overschrijdt de maximumwaarde [{3}]
+default.invalid.min.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is minder dan de minimumwaarde [{3}]
+default.invalid.max.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] overschrijdt de maximumgrootte van [{3}]
+default.invalid.min.size.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is minder dan mainimumgrootte van [{3}]
+default.invalid.validator.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] is niet geldig
+default.not.inlist.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] komt niet voor in de lijst [{3}]
+default.blank.message=Attribuut [{0}] van entiteit [{1}] mag niet leeg zijn
+default.not.equal.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] mag niet gelijk zijn aan [{3}]
+default.null.message=Attribuut [{0}] van entiteit [{1}] mag niet leeg zijn
+default.not.unique.message=Attribuut [{0}] van entiteit [{1}] met waarde [{2}] moet uniek zijn
+
+default.paginate.prev=Vorige
+default.paginate.next=Volgende
+
+# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
+typeMismatch.java.net.URL=Attribuut {0} is geen geldige URL
+typeMismatch.java.net.URI=Attribuut {0} is geen geldige URI
+typeMismatch.java.util.Date=Attribuut {0} is geen geldige datum
+typeMismatch.java.lang.Double=Attribuut {0} is geen geldig nummer
+typeMismatch.java.lang.Integer=Attribuut {0} is geen geldig nummer
+typeMismatch.java.lang.Long=Attribuut {0} is geen geldig nummer
+typeMismatch.java.lang.Short=Attribuut {0} is geen geldig nummer
+typeMismatch.java.math.BigDecimal=Attribuut {0} is geen geldig nummer
+typeMismatch.java.math.BigInteger=Attribuut {0} is geen geldig nummer
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_pt_BR.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_pt_BR.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_pt_BR.properties	(revision 875)
@@ -0,0 +1,34 @@
+#
+# Translated by Lucas Teixeira - lucastex@gmail.com
+#
+
+default.doesnt.match.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o atende ao padrÃ£o definido [{3}]
+default.invalid.url.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o Ã© uma URL vÃ¡lida
+default.invalid.creditCard.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o Ã© um nÃºmero vÃ¡lido de cartÃ£o de crÃ©dito
+default.invalid.email.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o Ã© um endereÃ§o de email vÃ¡lido.
+default.invalid.range.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o estÃ¡ entre a faixa de valores vÃ¡lida de [{3}] atÃ© [{4}]
+default.invalid.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o estÃ¡ na faixa de tamanho vÃ¡lida de [{3}] atÃ© [{4}]
+default.invalid.max.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapass o valor mÃ¡ximo [{3}]
+default.invalid.min.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o atinge o valor mÃ­nimo [{3}]
+default.invalid.max.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] ultrapassa o tamanho mÃ¡ximo de [{3}]
+default.invalid.min.size.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o atinge o tamanho mÃ­nimo de [{3}]
+default.invalid.validator.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o passou na validaÃ§Ã£o
+default.not.inlist.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o Ã© um valor dentre os permitidos na lista [{3}]
+default.blank.message=O campo [{0}] da classe [{1}] nÃ£o pode ficar em branco
+default.not.equal.message=O campo [{0}] da classe [{1}] com o valor [{2}] nÃ£o pode ser igual a [{3}]
+default.null.message=O campo [{0}] da classe [{1}] nÃ£o pode ser vazia
+default.not.unique.message=O campo [{0}] da classe [{1}] com o valor [{2}] deve ser Ãºnico
+
+default.paginate.prev=Anterior
+default.paginate.next=PrÃ³ximo
+
+# Mensagens de erro em atribuiÃ§Ã£o de valores. Use "typeMismatch.$className.$propertyName" para customizar (eg typeMismatch.Book.author)
+typeMismatch.java.net.URL=O campo {0} deve ser uma URL vÃ¡lida.
+typeMismatch.java.net.URI=O campo {0} deve ser uma URI vÃ¡lida.
+typeMismatch.java.util.Date=O campo {0} deve ser uma data vÃ¡lida
+typeMismatch.java.lang.Double=O campo {0} deve ser um nÃºmero vÃ¡lido.
+typeMismatch.java.lang.Integer=O campo {0} deve ser um nÃºmero vÃ¡lido.
+typeMismatch.java.lang.Long=O campo {0} deve ser um nÃºmero vÃ¡lido.
+typeMismatch.java.lang.Short=O campo {0} deve ser um nÃºmero vÃ¡lido.
+typeMismatch.java.math.BigDecimal=O campo {0} deve ser um nÃºmero vÃ¡lido.
+typeMismatch.java.math.BigInteger=O campo {0} deve ser um nÃºmero vÃ¡lido.
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_ru.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_ru.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_ru.properties	(revision 875)
@@ -0,0 +1,33 @@
+default.doesnt.match.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ ÐŸÐ±ÑÐ°Ð·ÑÑ [{3}]
+default.invalid.url.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ URL-Ð°ÐŽÑÐµÑÐŸÐŒ
+default.invalid.creditCard.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ ÐœÐŸÐŒÐµÑÐŸÐŒ ÐºÑÐµÐŽÐžÑÐœÐŸÐ¹ ÐºÐ°ÑÑÑ
+default.invalid.email.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ e-mail Ð°ÐŽÑÐµÑÐŸÐŒ
+default.invalid.range.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ Ð¿ÐŸÐ¿Ð°ÐŽÐ°ÐµÑ Ð² ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐ¹ ÐžÐœÑÐµÑÐ²Ð°Ð» ÐŸÑ [{3}] ÐŽÐŸ [{4}]
+default.invalid.size.message=Ð Ð°Ð·ÐŒÐµÑ Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] (Ð·ÐœÐ°ÑÐµÐœÐžÐµ: [{2}]) ÐœÐµ Ð¿ÐŸÐ¿Ð°ÐŽÐ°ÐµÑ Ð² ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐ¹ ÐžÐœÑÐµÑÐ²Ð°Ð» ÐŸÑ [{3}] ÐŽÐŸ [{4}]
+default.invalid.max.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] Ð±ÐŸÐ»ÑÑÐµ ÑÐµÐŒ ÐŒÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ [{3}]
+default.invalid.min.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐŒÐµÐœÑÑÐµ ÑÐµÐŒ ÐŒÐžÐœÐžÐŒÐ°Ð»ÑÐœÐŸ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ [{3}]
+default.invalid.max.size.message=Ð Ð°Ð·ÐŒÐµÑ Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] (Ð·ÐœÐ°ÑÐµÐœÐžÐµ: [{2}]) Ð±ÐŸÐ»ÑÑÐµ ÑÐµÐŒ ÐŒÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐ¹ ÑÐ°Ð·ÐŒÐµÑ [{3}]
+default.invalid.min.size.message=Ð Ð°Ð·ÐŒÐµÑ Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] (Ð·ÐœÐ°ÑÐµÐœÐžÐµ: [{2}]) ÐŒÐµÐœÑÑÐµ ÑÐµÐŒ ÐŒÐžÐœÐžÐŒÐ°Ð»ÑÐœÐŸ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐ¹ ÑÐ°Ð·ÐŒÐµÑ [{3}]
+default.invalid.validator.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÐŸ
+default.not.inlist.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ Ð¿ÐŸÐ¿Ð°ÐŽÐ°ÐµÑ Ð² ÑÐ¿ÐžÑÐŸÐº ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ [{3}]
+default.blank.message=ÐÐŸÐ»Ðµ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÑÑÑÐŒ
+default.not.equal.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÑÐ°Ð²ÐœÐŸ [{3}]
+default.null.message=ÐÐŸÐ»Ðµ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐœÐµ ÐŒÐŸÐ¶ÐµÑ ÐžÐŒÐµÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ null
+default.not.unique.message=ÐÐœÐ°ÑÐµÐœÐžÐµ [{2}] Ð¿ÐŸÐ»Ñ [{0}] ÐºÐ»Ð°ÑÑÐ° [{1}] ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð±ÑÑÑ ÑÐœÐžÐºÐ°Ð»ÑÐœÑÐŒ
+
+default.paginate.prev=ÐÑÐµÐŽÑÐŽÑÑÐ°Ñ ÑÑÑÐ°ÐœÐžÑÐ°
+default.paginate.next=Ð¡Ð»ÐµÐŽÑÑÑÐ°Ñ ÑÑÑÐ°ÐœÐžÑÐ°
+
+# ÐÑÐžÐ±ÐºÐž Ð¿ÑÐž Ð¿ÑÐžÑÐ²ÐŸÐµÐœÐžÐž ÐŽÐ°ÐœÐœÑÑ
+. ÐÐ»Ñ ÑÐŸÑÐœÐŸÐ¹ ÐœÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐŽÐ»Ñ Ð¿ÐŸÐ»ÐµÐ¹ ÐºÐ»Ð°ÑÑÐŸÐ² ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ
+# ÑÐŸÑÐŒÐ°Ñ "typeMismatch.$className.$propertyName" (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, typeMismatch.Book.author)
+typeMismatch.java.net.URL=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ URL
+typeMismatch.java.net.URI=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ URI
+typeMismatch.java.util.Date=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÐŸÐ¹ ÐŽÐ°ÑÐŸÐ¹
+typeMismatch.java.lang.Double=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ ÑÐžÑÐ»ÐŸÐŒ
+typeMismatch.java.lang.Integer=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ ÑÐžÑÐ»ÐŸÐŒ
+typeMismatch.java.lang.Long=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ ÑÐžÑÐ»ÐŸÐŒ
+typeMismatch.java.lang.Short=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ ÑÐžÑÐ»ÐŸÐŒ
+typeMismatch.java.math.BigDecimal=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ ÑÐžÑÐ»ÐŸÐŒ
+typeMismatch.java.math.BigInteger=ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ {0} ÐœÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÑÐŒ ÑÐžÑÐ»ÐŸÐŒ
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_th.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_th.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_th.properties	(revision 875)
@@ -0,0 +1,30 @@
+default.doesnt.match.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹àžàž¹àžàžà¹àž­àžàžàž²àž¡àž£àž¹àžà¹àžàžàžàžµà¹àžàž³àž«àžàžà¹àž§à¹à¹àž [{3}]
+default.invalid.url.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹àžàž¹àžàžà¹àž­àžàžàž²àž¡àž£àž¹àžà¹àžàž URL
+default.invalid.creditCard.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹àžàž¹àžàžà¹àž­àžàžàž²àž¡àž£àž¹àžà¹àžàžàž«àž¡àž²àž¢à¹àž¥àžàžàž±àžàž£à¹àžàž£àžàžŽàž
+default.invalid.email.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹àžàž¹àžàžà¹àž­àžàžàž²àž¡àž£àž¹àžà¹àžàžàž­àžµà¹àž¡àž¥à¹
+default.invalid.range.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹à¹àžà¹àž¡àžµàžà¹àž²àžàžµà¹àžàž¹àžàžà¹àž­àžà¹àžàžà¹àž§àžàžàž²àž [{3}] àžàž¶àž [{4}]
+default.invalid.size.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹à¹àžà¹àž¡àžµàžàžàž²àžàžàžµà¹àžàž¹àžàžà¹àž­àžà¹àžàžà¹àž§àžàžàž²àž [{3}] àžàž¶àž [{4}]
+default.invalid.max.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] àž¡àžµàžà¹àž²à¹àžàžŽàžàžàž§à¹àž²àžà¹àž²àž¡àž²àžàžªàžžàž [{3}]
+default.invalid.min.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] àž¡àžµàžà¹àž²àžà¹àž­àž¢àžàž§à¹àž²àžà¹àž²àžà¹àž³àžªàžžàž  [{3}]
+default.invalid.max.size.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] àž¡àžµàžàžàž²àžà¹àžàžŽàžàžàž§à¹àž²àžàžàž²àžàž¡àž²àžàžªàžžàžàžàž­àž [{3}]
+default.invalid.min.size.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] àž¡àžµàžàžàž²àžàžà¹àž³àžàž§à¹àž²àžàžàž²àžàžà¹àž³àžªàžžàžàžàž­àž  [{3}]
+default.invalid.validator.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹àžà¹àž²àžàžàž²àž£àžàž§àžàžªàž­àžàžà¹àž²àžàžµà¹àžàž±à¹àžàžàž¶à¹àž
+default.not.inlist.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹à¹àžà¹àž­àž¢àž¹à¹à¹àžàž£àž²àž¢àžàž²àž£àžà¹àž­à¹àžàžàžµà¹  [{3}]
+default.blank.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] à¹àž¡à¹àžªàž²àž¡àž²àž£àžà¹àžà¹àžàžà¹àž²àž§à¹àž²àžà¹àžà¹
+default.not.equal.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] à¹àž¡à¹àžªàž²àž¡àž²àž£àžà¹àžà¹àž²àžàž±àž [{3}] à¹àžà¹
+default.null.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] à¹àž¡à¹àžªàž²àž¡àž²àž£àžà¹àžà¹àž null à¹àžà¹
+default.not.unique.message=àžàžžàžàžªàž¡àžàž±àžàžŽ [{0}] àžàž­àžàžàž¥àž²àžª [{1}] àžàž¶à¹àžàž¡àžµàžà¹àž²à¹àžà¹àž [{2}] àžàž°àžà¹àž­àžà¹àž¡à¹àžà¹àž³ (unique)
+
+default.paginate.prev=àžà¹àž­àžàž«àžà¹àž²
+default.paginate.next=àžàž±àžà¹àž
+
+# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author)
+typeMismatch.java.net.URL=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžà¹àžà¹àžàžà¹àž² URL àžàžµà¹àžàž¹àžàžà¹àž­àž
+typeMismatch.java.net.URI=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžà¹àžà¹àžàžà¹àž² URI àžàžµà¹àžàž¹àžàžà¹àž­àž
+typeMismatch.java.util.Date=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžàž¡àžµàžà¹àž²à¹àžà¹àžàž§àž±àžàžàžµà¹
+typeMismatch.java.lang.Double=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžàž¡àžµàžà¹àž²à¹àžà¹àžàžàž³àžàž§àžàžàž£àž°à¹àž àž Double
+typeMismatch.java.lang.Integer=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžàž¡àžµàžà¹àž²à¹àžà¹àžàžàž³àžàž§àžàžàž£àž°à¹àž àž Integer
+typeMismatch.java.lang.Long=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžàž¡àžµàžà¹àž²à¹àžà¹àžàžàž³àžàž§àžàžàž£àž°à¹àž àž Long
+typeMismatch.java.lang.Short=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžàž¡àžµàžà¹àž²à¹àžà¹àžàžàž³àžàž§àžàžàž£àž°à¹àž àž Short
+typeMismatch.java.math.BigDecimal=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžàž¡àžµàžà¹àž²à¹àžà¹àžàžàž³àžàž§àžàžàž£àž°à¹àž àž BigDecimal
+typeMismatch.java.math.BigInteger=àžàžžàžàžªàž¡àžàž±àžàžŽ '{0}' àžàž°àžà¹àž­àžàž¡àžµàžà¹àž²à¹àžà¹àžàžàž³àžàž§àžàžàž£àž°à¹àž àž BigInteger
Index: /branches/features/grailsUpgrade/grails-app/i18n/messages_zh_CN.properties
===================================================================
--- /branches/features/grailsUpgrade/grails-app/i18n/messages_zh_CN.properties	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/i18n/messages_zh_CN.properties	(revision 875)
@@ -0,0 +1,18 @@
+default.blank.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u4E0D\u80FD\u4E3A\u7A7A
+default.doesnt.match.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0E\u5B9A\u4E49\u7684\u6A21\u5F0F [{3}]\u4E0D\u5339\u914D
+default.invalid.creditCard.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u4FE1\u7528\u5361\u53F7
+default.invalid.email.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u7535\u5B50\u90AE\u4EF6\u5730\u5740
+default.invalid.max.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u6BD4\u6700\u5927\u503C [{3}]\u8FD8\u5927
+default.invalid.max.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u6BD4\u6700\u5927\u503C [{3}]\u8FD8\u5927
+default.invalid.min.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u6BD4\u6700\u5C0F\u503C [{3}]\u8FD8\u5C0F
+default.invalid.min.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u6BD4\u6700\u5C0F\u503C [{3}]\u8FD8\u5C0F
+default.invalid.range.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u5728\u5408\u6CD5\u7684\u8303\u56F4\u5185( [{3}] \uFF5E [{4}] )
+default.invalid.size.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u7684\u5927\u5C0F\u4E0D\u5728\u5408\u6CD5\u7684\u8303\u56F4\u5185( [{3}] \uFF5E [{4}] )
+default.invalid.url.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684URL
+default.invalid.validator.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u672A\u80FD\u901A\u8FC7\u81EA\u5B9A\u4E49\u7684\u9A8C\u8BC1
+default.not.equal.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0E[{3}]\u4E0D\u76F8\u7B49
+default.not.inlist.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u4E0D\u5728\u5217\u8868\u7684\u53D6\u503C\u8303\u56F4\u5185
+default.not.unique.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u7684\u503C[{2}]\u5FC5\u987B\u662F\u552F\u4E00\u7684
+default.null.message=[{1}]\u7C7B\u7684\u5C5E\u6027[{0}]\u4E0D\u80FD\u4E3Anull
+default.paginate.next=\u4E0B\u9875
+default.paginate.prev=\u4E0A\u9875
Index: /branches/features/grailsUpgrade/grails-app/jobs/InventoryIndexJob.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/jobs/InventoryIndexJob.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/jobs/InventoryIndexJob.groovy	(revision 875)
@@ -0,0 +1,39 @@
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+
+/**
+* Provides a quartz job that rebuilds the searchable index for the inventory search.
+* With concurrent=false the next job is blocked until the previous job completes.
+* We need a hibernate session otherwise we get a LazyInitializationException, default is true but we specify it to be sure.
+* Rebuilding the index is required since searchable components are not updated when they change, that is
+* until the parent is updated and reindexed. Cascade update is broken in searchable-0.5.5
+*/
+class InventoryIndexJob {
+
+    def concurrent = false
+    def sessionRequired = true
+
+    static triggers = {
+        // Cron fields:
+        // 'Seconds Minutes Hours DOM Month DOW Year(Optional)'
+        // See: http://www.quartz-scheduler.org/docs/tutorials/crontrigger.html
+        // Trigger every hour on the hour:
+        //cron name: 'RebuildInventoryIndex', cronExpression: "0 0 * * * ?"
+    }
+
+    def execute(context) {
+
+        // Some information can be accessed if we run with "def execute(context) ".
+        // For more info see: http://quartz.sourceforge.net/javadoc/org/quartz/JobExecutionContext.html
+        // log.debug context.getTrigger()
+        // log.debug context.getPreviousFireTime()
+        // log.debug context.getFireTime()
+
+        // Called by.
+        def calledBy =  context.mergedJobDataMap.get('calledBy')
+        log.info "Called By: " + calledBy
+
+        // Rebuild the Inventory searchable index.
+        log.info "Calling, Inventory.index()."
+        InventoryItem.index()
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/jobs/TaskRecurringScheduleJob.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/jobs/TaskRecurringScheduleJob.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/jobs/TaskRecurringScheduleJob.groovy	(revision 875)
@@ -0,0 +1,35 @@
+import org.codehaus.groovy.grails.commons.*
+
+/**
+* Provides a quartz job that reviews and generates all recurring tasks.
+* The quartz scheduler is restarted if this file is edited so startDelay will then delay again.
+* The execute method is called once every repeatInterval (in milliseconds).
+* With concurrent=false the next job is blocked until the previous job completes.
+* Apparently we need a hibernate session otherwise we get a LazyInitializationException, default is true but we specify it to be sure.
+*/
+class TaskRecurringScheduleJob {
+
+    def taskRecurringScheduleService
+
+    def concurrent = false
+    def sessionRequired = true
+
+    // The repeatInterval starts counting again after firing, but concurrent = false may block firing until the previous job completes.
+    static triggers = {
+        simple name: "GenerateAll",
+                    startDelay: 60000,
+                    repeatInterval: ConfigurationHolder.config.taskRecurringScheduleJob.repeatInterval*1000
+    }
+
+    def execute() {
+
+        // Some information can be accessed if we run with "def execute(context) ".
+        // For more info see: http://quartz.sourceforge.net/javadoc/org/quartz/JobExecutionContext.html
+        // log.debug context.getTrigger()
+        // log.debug context.getPreviousFireTime()
+        // log.debug context.getFireTime()
+
+        // We do everything via services, quartz just sets up and fires off the thread.
+        taskRecurringScheduleService.generateAll()
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/services/AddressService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AddressService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AddressService.groovy	(revision 875)
@@ -0,0 +1,70 @@
+/**
+ * Provides a service class with methods to interact with Address domain class.
+ * Address stores the address for various objects in the database.
+ */
+class AddressService {
+
+    boolean transactional = false
+
+    def getAddress() {
+        """${this.street1}
+        ${this.street2}
+        ${this.city}
+        ${this.state}
+        ${this.postCode}
+        ${this.country}"""
+
+    }
+
+    def create(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["Address", params.id] ]
+            return result
+        }
+
+        if(!checkForOwner(params))
+            return fail(code:"address.owner.not.found")
+
+        result.addressInstance = new Address()
+        result.addressInstance.properties = params
+
+        // success
+        return result
+    }
+
+    def save(params) {
+        def result = [:]
+        def fail = { Map m ->
+            if(result.addressInstance && m.field)
+                result.addressInstance.errors.rejectValue(m.field, m.code)
+            result.error = [ code: m.code, args: ["Address", params.id] ]
+            return result
+        }
+
+        if(!checkForOwner(params))
+            return fail(code:"address.owner.not.found")
+
+        result.addressInstance = new Address(params)
+
+        if(result.addressInstance.hasErrors() || !result.addressInstance.save(flush: true))
+            return fail(code:"default.create.failure")
+
+        // success
+        return result
+    }
+
+    private checkForOwner(params) {
+
+        if(params.supplier?.id)
+            return Supplier.exists(params.supplier.id)
+        if(params.person?.id)
+            return Person.exists(params.person.id)
+        if(params.site?.id)
+            return Site.exists(params.site.id)
+
+        return false
+    }
+
+
+} // end of class
Index: /branches/features/grailsUpgrade/grails-app/services/AppConfigService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AppConfigService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AppConfigService.groovy	(revision 875)
@@ -0,0 +1,56 @@
+/**
+ * Provides a service class with methods to interact with AppConfig.
+ * AppConfig stores various application configuration (settings) in the database.
+ */
+class AppConfigService {
+
+    boolean transactional = false
+
+    /**
+    * Set the value of an appConfig.
+    * @param name The name of the appConfig.
+    * @param value Set to this value if specified else defaults to "true".
+    * @returns True if success otherwise false.
+    */
+    public Boolean set(String name, String value = "true") {
+        def appConfig = AppConfig.findByName(name)
+        appConfig ? (appConfig.value = value) : (appConfig = new AppConfig(name: name, value: value))
+        appConfig.save() ? true : false
+    }
+
+    /**
+    * Check if an appConfig exists.
+    * @param name The name of the appConfig.
+    * @returns True if success otherwise false.
+    */
+    public Boolean exists(String name) {
+        AppConfig.findByName(name) ? true : false
+    }
+
+    /**
+    * Get the value of an appConfig.
+    * @param name The name of the appConfig.
+    * @returns The value of the appConfig else false.
+    */
+    def getValue(String name) {
+        def appConfig = AppConfig.findByName(name)
+        appConfig ? appConfig.value : false
+    }
+
+    /**
+    * Delete an appConfig.
+    * @param name The name of the appConfig.
+    * @returns True if success otherwise false.
+    */
+    public Boolean delete(String name) {
+        try {
+            AppConfig.findByName(name).delete(flush:true)
+            return true
+        }
+        catch(e) {
+            log.debug("Could not delete, appConfig may not exist.")
+            return false
+        }
+    }
+
+} // end of class
Index: /branches/features/grailsUpgrade/grails-app/services/AssetCsvService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AssetCsvService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AssetCsvService.groovy	(revision 875)
@@ -0,0 +1,471 @@
+import grails.util.GrailsUtil
+import au.com.bytecode.opencsv.CSVWriter
+import au.com.bytecode.opencsv.CSVReader
+import org.apache.commons.lang.WordUtils
+
+/**
+ * Provides some csv import/export methods.
+ * Requires the opencsv jar to be available which is included in the grails-export plugin.
+ */
+class AssetCsvService {
+
+    boolean transactional = false
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    def sessionFactory
+    def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
+
+    /**
+    * Import an asset tree creating items as required.
+    * @param request The http request to run getFile against.
+    * Get file should return a csv format file containing the asset tree as per template.
+    */
+    def importAssetTree(request) {
+        Asset.withTransaction { status ->
+            def result = [:]
+
+            def kByteMultiplier = 1000
+            def fileMaxSize = 500 * kByteMultiplier
+            def logFileLink = g.link(controller: "appCore", action: "appLog") {"log"}
+
+            def multiPartFile = request.getFile('file')
+
+            InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
+            CSVReader reader = new CSVReader(sr)
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                reader.close()
+                result.error = [ code: m.code, args: m.args ]
+                return result
+            }
+
+            if(!multiPartFile || multiPartFile.isEmpty())
+                return fail(code: "default.file.not.supplied")
+
+            if (multiPartFile.getSize() > fileMaxSize)
+                return fail(code: "default.file.over.max.size", args: [fileMaxSize/kByteMultiplier, "kB"])
+
+            def columnIndex = 0
+            def nameColumnIndex = 0
+            def numberOfColumns = 0
+            def maxNumberOfColumns = 20
+
+            // Get first line.
+            def line = reader.readNext()
+            def lineNumber = 1
+
+            // Check for header line 1.
+            if(line != templateHeaderLine1) {
+                log.error "Failed to find header line 1. "
+                log.error "Required: " + templateHeaderLine1.toString()
+                log.error "Supplied: " + line.toString()
+                return fail(code: "default.file.no.header")
+            }
+
+            // Get second line.
+            line = reader.readNext()
+            lineNumber ++
+
+            // Check for header line 2.
+            if(line != templateHeaderLine2) {
+                log.error "Failed to find header line 2. "
+                log.error "Required: " + templateHeaderLine2.toString()
+                log.error "Supplied: " + line.toString()
+                return fail(code: "default.file.no.header")
+            }
+
+            log.info "Import checks passed, start processing asset file."
+
+            // Prepare the first body line.
+            line = reader.readNext()
+            lineNumber ++
+
+            def siteInstance
+            def departmentInstance
+            def sectionInstance
+            def assetInstance
+            def assetSubItemInstance
+            def parentItem
+
+            def column = [:]
+
+            def nextLine = {
+                    line = reader.readNext()
+                    lineNumber ++
+                    log.info "Processing line: " + lineNumber
+            }
+
+            def nextColumn = {
+                nameColumnIndex = columnIndex
+
+                if( (columnIndex+1) < numberOfColumns ) {
+                    // Capitalise and assign the name and description columns.
+                    use(WordUtils) {
+                    column.name = line[columnIndex].trim().capitalize()
+                    column.description = line[++columnIndex].trim().capitalize()
+                    }
+                }
+                else if( columnIndex < numberOfColumns ) {
+                    // Capitalise and assign the name column with a blank description.
+                    use(WordUtils) {
+                    column.name = line[columnIndex].trim().capitalize()
+                    column.description = ''
+                    }
+                }
+                else {
+                    log.info "No more columns on line: " + lineNumber
+                    return false
+                }
+
+                if(!column.name) {
+                    log.info "No name at " + "line: " + lineNumber + " col: " + nameColumnIndex
+                    return false
+                }
+
+                columnIndex++
+                // Success.
+                return column
+            }
+
+            // Primary loop.
+            while(line) {
+                numberOfColumns = Math.min( line.size(), maxNumberOfColumns )
+                columnIndex = 0
+
+                if(!nextColumn()) {
+                    nextLine()
+                    continue
+                }
+
+                // Ignore comment lines.
+                if(line.toString().toLowerCase().contains("comment")) {
+                    log.info "Comment line found."
+                    nextLine()
+                    continue
+                }
+
+                // Ignore example lines.
+                if(line.toString().toLowerCase().contains("example")) {
+                    log.info "Example line found."
+                    nextLine()
+                    continue
+                }
+
+                // Site.
+                siteInstance = Site.findByName(column.name)
+                if(!siteInstance) {
+                    log.info "Creating site: " + column.name
+                    siteInstance = new Site(name: column.name,
+                                                                description: column.description)
+                    if(!siteInstance.save()) {
+                        log.error "Failed to create site on line: " + column.name + "(" + lineNumber + ")"
+                        return fail(code: "asset.tree.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+                else log.info "Existing site: " + siteInstance
+
+                if(!nextColumn()) {
+                    nextLine()
+                    continue
+                }
+
+                // Department.
+                departmentInstance = Department.findByName(column.name)
+                if(!departmentInstance) {
+                    log.info "Creating department: " + column.name
+                    departmentInstance = new Department(name: column.name,
+                                                                                            description: column.description,
+                                                                                            site: siteInstance)
+                    if(!departmentInstance.save()) {
+                        log.error "Failed to create department on line: " + column.name + "(" + lineNumber + ")"
+                        return fail(code: "asset.tree.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+                else log.info "Existing department: " + departmentInstance
+
+                if(!nextColumn()) {
+                    nextLine()
+                    continue
+                }
+
+                // Section.
+                sectionInstance = Section.findByName(column.name)
+                if(!sectionInstance) {
+                    log.info "Creating section: " + column.name
+                    sectionInstance =  new Section(name: column.name,
+                                                                            description: column.description,
+                                                                            site: siteInstance,
+                                                                            department: departmentInstance)
+                    if(!sectionInstance.save()) {
+                        log.error "Failed to create section on line: " + column.name + "(" + lineNumber + ")"
+                        return fail(code: "asset.tree.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+                else log.info "Existing section: " + sectionInstance
+
+                if(!nextColumn()) {
+                    nextLine()
+                    continue
+                }
+
+                // Asset.
+                assetInstance = Asset.findByName(column.name)
+                if(!assetInstance) {
+                    log.info "Creating asset: " + column.name
+                    assetInstance = new Asset(name: column.name,
+                                                                    description: column.description,
+                                                                    section: sectionInstance)
+                    if(!assetInstance.save()) {
+                        log.error "Failed to create asset on line: " + column.name + "(" + lineNumber + ")"
+                        return fail(code: "asset.tree.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+                else log.info "Existing asset: " + assetInstance
+
+                if(!nextColumn()) {
+                    nextLine()
+                    continue
+                }
+
+                // AssetSubItem Level 1.
+                assetSubItemInstance = AssetSubItem.findByName(column.name)
+                if(!assetSubItemInstance) {
+                    log.info "Creating asset sub item: " + column.name
+                    assetSubItemInstance = new AssetSubItem(name: column.name,
+                                                                                                description: column.description)
+                    if(!assetInstance.save()) {
+                        log.error "Failed to create assetSubItem on line: " + column.name + "(" + lineNumber + ")"
+                        return fail(code: "asset.tree.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+                else log.info "Existing asset sub item: " + assetSubItemInstance
+
+                assetInstance.addToAssetSubItems(assetSubItemInstance)
+
+                // Remaining AssetSubItems.
+                while( nextColumn() ) {
+
+                    parentItem = assetSubItemInstance
+                    assetSubItemInstance = AssetSubItem.findByName(column.name)
+                    if(!assetSubItemInstance) {
+                        log.info "Creating asset sub item: " + column.name
+                        assetSubItemInstance = new AssetSubItem(name: column.name,
+                                                                                                    description: column.description,
+                                                                                                    parentItem: parentItem)
+                        if(!assetSubItemInstance.save()) {
+                            log.error "Failed to create assetSubItem on line: " + column.name + "(" + lineNumber + ")"
+                            return fail(code: "asset.tree.import.failure", args: [lineNumber, logFileLink])
+                        }
+                    }
+                    else log.info "Existing asset sub item: " + assetSubItemInstance
+
+                } // while( nextColumn() )
+
+                if(lineNumber % 100 == 0)
+                    cleanUpGorm()
+
+                nextLine()
+            } //while(line)
+
+            // Success.
+            log.info "End of file."
+            reader.close()
+            return result
+
+        } //end withTransaction
+    } // end importAssetTree()
+
+    /**
+    * Build an asset tree template csv file.
+    * This template can then be populated for import.
+    * @returns The template as a String in csv format.
+    */
+    def buildAssetTreeTemplate() {
+
+        StringWriter sw = new StringWriter()
+        CSVWriter writer = new CSVWriter(sw)
+
+        writeTemplateLines(writer)
+
+        writer.close()
+        return sw.toString()
+    }
+
+    private writeTemplateLines(writer) {
+        writer.writeNext(templateHeaderLine1 as String[])
+        writer.writeNext(templateHeaderLine2 as String[])
+        writer.writeNext()
+        writer.writeNext(["Example: Site1", "", "Department 1", "", "Section 1", "", "Asset 1", ""] as String[])
+        writer.writeNext()
+        writer.writeNext(["Example: Site1", "", "Department 1", "", "Section 1", "", "Asset 2", ""] as String[])
+        writer.writeNext()
+        writer.writeNext("Comment: The first two header lines are required.")
+        writer.writeNext("Comment: Leave a blank line between assets.")
+        writer.writeNext("Comment: Names are required, descriptions are optional.")
+        writer.writeNext("Comment: Identical and existing names will be considered as the same item.")
+        writer.writeNext("Comment: An asset may share the first level of asset sub items with other assets.")
+        writer.writeNext("Comment: Lower levels of asset sub items are only parented once but may have many children.")
+        writer.writeNext("Comment: Lines containing 'comment' will be ignored.")
+        writer.writeNext("Comment: Lines containing 'example' will be ignored.")
+        writer.writeNext("Comment: This file must be saved as a CSV file before import.")
+        writer.writeNext()
+    }
+
+    /**
+    * Build an asset tree test file.
+    * This test file can be imported to test the import and template methods.
+    * @returns The test file as a String in csv format.
+    */
+    def buildAssetTreeTest() {
+
+        StringWriter sw = new StringWriter()
+        CSVWriter writer = new CSVWriter(sw)
+
+        writeTemplateLines(writer)
+
+        writer.writeNext(["Lake Press", "Lake Press Site",
+                                        "Print Department", "The printing department",
+                                        "Press Section", "Contains all printing units",
+                                        "Print Unit 1", "Printing Unit Number 1",
+                                        "Print Unit", "Print Unit (Common to all units)",
+                                        "Print Couple", "Includes  blanket cylinder",
+                                        "Motor", "Main Drive Motor",
+                                        "NDS Bearing", "Non Drive Side Main Bearing"
+                                        ] as String[])
+
+        writer.writeNext(["Lake Press", "Lake Press Site",
+                                        "Print Department", "The printing department",
+                                        "Press Section", "Contains all printing units",
+                                        "Print Unit 1", "Printing Unit Number 1",
+                                        "Print Unit", "Print Unit (Common to all units)",
+                                        "Print Couple", "Includes  blanket cylinder",
+                                        "Motor", "Main Drive Motor",
+                                        "DS Bearing", "Drive Side Main Bearing"
+                                        ] as String[])
+
+        writer.close()
+        return sw.toString()
+    }
+
+    /**
+    * Build complete asset trees for export.
+    * @param assetList The list of assets to build and export trees for.
+    * @returns The tree as a String in csv format.
+    */
+    def buildAssetTree(List assetList) {
+
+        StringWriter sw = new StringWriter()
+        CSVWriter writer = new CSVWriter(sw)
+
+        writeTemplateLines(writer)
+
+        //Rows
+        def row
+
+        def writeAssetSubItem4 = { assetSubItem ->
+            row.add(assetSubItem.name)
+            row.add(assetSubItem.description)
+            writer.writeNext(row as String[])
+        }
+
+        def writeAssetSubItem3 = { assetSubItem ->
+            row.add(assetSubItem.name)
+            row.add(assetSubItem.description)
+
+            if(assetSubItem.subItems.size() > 0) {
+                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem4 ->
+                    writeAssetSubItem4(assetSubItem4)
+                    row.removeRange(row.size()-2, row.size())
+                }
+            }
+            else {
+                writer.writeNext(row as String[])
+            }
+
+        }
+
+        def writeAssetSubItem2 = { assetSubItem ->
+            row.add(assetSubItem.name)
+            row.add(assetSubItem.description)
+
+            if(assetSubItem.subItems.size() > 0) {
+                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem3 ->
+                    writeAssetSubItem3(assetSubItem3)
+                    row.removeRange(row.size()-2, row.size())
+                }
+            }
+            else {
+                writer.writeNext(row as String[])
+            }
+
+        }
+
+        def writeAssetSubItem1 = { assetSubItem ->
+            row.add(assetSubItem.name)
+            row.add(assetSubItem.description)
+
+            if(assetSubItem.subItems.size() > 0) {
+                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem2 ->
+                    writeAssetSubItem2(assetSubItem2)
+                    row.removeRange(row.size()-2, row.size())
+                }
+            }
+            else {
+                writer.writeNext(row as String[])
+            }
+
+        }
+
+        assetList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { asset ->
+            row = []
+            writer.writeNext(row as String[]) //blank row between assets.
+            row.add(asset.section.site.name)
+            row.add(asset.section.site.description)
+            row.add(asset.section.department.name)
+            row.add(asset.section.department.description)
+            row.add(asset.section.name)
+            row.add(asset.section.description)
+            row.add(asset.name)
+            row.add(asset.description)
+
+            if(asset.assetSubItems.size() > 0) {
+                asset.assetSubItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem1 ->
+                    writeAssetSubItem1(assetSubItem1)
+                    row.removeRange(row.size()-2, row.size())
+                }
+            }
+            else {
+                writer.writeNext(row as String[])
+            }
+
+        }
+
+        writer.close()
+        return sw.toString()
+    } // end buildAssetTree
+
+    private getTemplateHeaderLine1() {
+            ["Site", "", "Department", "", "Section", "","Asset", "", "Sub Asset", "", "Functional Assembly", "", "Sub Assembly Group", "", "SubItem", ""]
+    }
+
+    private getTemplateHeaderLine2() {
+            (["Name", "Description"])*8
+    }
+
+    /**
+    * This cleans up the hibernate session and a grails map.
+    * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
+    * The hibernate session flush is normal for hibernate.
+    * The map is apparently used by grails for domain object validation errors.
+    * A starting point for clean up is every 100 objects.
+    */
+    def cleanUpGorm() {
+        def session = sessionFactory.currentSession
+        session.flush()
+        session.clear()
+        propertyInstanceMap.get().clear()
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/AssetReportService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AssetReportService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AssetReportService.groovy	(revision 875)
@@ -0,0 +1,476 @@
+import net.kromhouts.HqlBuilder
+
+/**
+* Service class that encapsulates the business logic for Asset Reports.
+*/
+class AssetReportService {
+
+    boolean transactional = false
+
+    def authService
+    def dateUtilService
+//     def messageSource
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    def paramsMax = 100000
+
+    /**
+    * Selects and returns the assets and their details.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getAssetRegister(params, locale) {
+        def result = [:]
+
+        result.section = Section.get(params.section.id.toLong())
+        result.site = result.section.site
+
+        // Inner join used to return only attribTypes that are used by AssetExtendedAttributes.
+        // So the result is only asset extendedAttributeTypes.
+//         def attribTypesQ = new HqlBuilder().query {
+//             select 'distinct attribT.name'
+//             from 'AssetExtendedAttribute attrib',
+//                     'join attrib.extendedAttributeType as attribT'
+//             order 'by attribT.name asc'
+//         }
+
+        // All active ExtendedAttributes.
+        def attribTypesQ = new HqlBuilder().query {
+            select 'distinct attribT.name'
+            from 'ExtendedAttributeType attribT'
+            where 'attribT.isActive = true'
+            order 'by attribT.name asc'
+        }
+        result.attribTypes = ExtendedAttributeType.executeQuery(attribTypesQ.query, attribTypesQ.namedParams)
+
+        // A result is returned for every asset and for any extended attributes.
+        def q = new HqlBuilder().query {
+            select 'new map(asset.name as name',
+                        'asset.description as description',
+                        'asset.comment as comment',
+                        'attribT.name as attribType',
+                        'attrib.value as attribValue)'
+            from 'Asset asset',
+                    'left join asset.assetExtendedAttributes as attrib',
+                    'left join attrib.extendedAttributeType as attribT'
+            where 'asset.section = :section'
+                    namedParams.section = result.section
+            order 'by asset.name asc, attribT.name asc'
+        }
+        def assetResults = Asset.executeQuery(q.query, q.namedParams)
+
+        // Build the report table row for each asset.
+        // Rows are keyed by asset.name and the value is a Map of the attributes.
+        def rows = [:]
+        assetResults.each { assetResult ->
+            // Create row if it does not exist yet.
+            if(!rows.containsKey(assetResult.name)) {
+                rows[assetResult.name] = ['name':assetResult.name,
+                                                            'description':assetResult.description,
+                                                            'comment':assetResult.comment]
+
+                // Add all attribType columns.
+                result.attribTypes.each { column ->
+                    rows[assetResult.name][column] = ' '
+                }
+            }
+
+            // Assign value to column.
+            rows[assetResult.name][assetResult.attribType] = assetResult.attribValue
+        }
+
+        // The value of each row is the dataList used by the report table.
+        result.dataList = rows.collect {it.value}
+
+        // Success.
+        return result
+
+    } // getAssetRegister
+
+    /**
+    * Selects and returns an asset (or all) and its details.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getAssetDetail(params, locale) {
+        //def result = [:]
+        def result
+
+        //result.summaryOfCalculationMethod = ''
+
+        // A result is returned for every asset and for any extended attributes.
+        // The report then groups by asset.name
+        def q = new HqlBuilder().query {
+            select 'new map(asset.name as name',
+                        'asset.description as description',
+                        'asset.comment as comment',
+                        'attribT.name as attribType',
+                        'attrib.value as attribValue)'
+            from 'Asset asset',
+                    'left join asset.assetExtendedAttributes as attrib',
+                    'left join attrib.extendedAttributeType as attribT'
+            if(params.section instanceof Section) {
+                namedParams.section = params.section
+                where 'asset.section = :section'
+            }
+            order 'by asset.name asc, attribT.name asc'
+        }
+
+        // result.dataList = Asset.list()
+        result = Asset.executeQuery(q.query, q.namedParams)
+
+        // Success.
+        return result
+
+    } // getAssetDetail
+
+    /**
+    * Selects and returns level 1 sub items (aka machines or equipment) and their details.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getEquipmentRegister(params, locale) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: [] ]
+            return result
+        }
+
+        result.section = Section.get(params.section.id.toLong())
+        result.site = result.section.site
+
+        result.startDate = params.startDate ?: dateUtilService.oneWeekAgo
+        result.endDate = params.endDate ?: dateUtilService.today
+        // Auto swap date range.
+        if(result.startDate > result.endDate) {
+            def tempStartDate = result.startDate
+            result.startDate = result.endDate
+            result.endDate = tempStartDate
+        }
+
+        result.startDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startDate)
+        result.endDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.endDate)
+
+        // Inner join used to return only attribTypes that are used by AssetSubItemExtendedAttributes.
+        // So the result is only assetSubItem extendedAttributeTypes.
+//         def attribTypesQ = new HqlBuilder().query {
+//             select 'distinct attribT.name'
+//             from 'AssetSubItemExtendedAttribute attrib',
+//                     'join attrib.extendedAttributeType as attribT'
+//             order 'by attribT.name asc'
+//         }
+
+        // All active ExtendedAttributes.
+        def attribTypesQ = new HqlBuilder().query {
+            select 'distinct attribT.name'
+            from 'ExtendedAttributeType attribT'
+            where 'attribT.isActive = true'
+            order 'by attribT.name asc'
+        }
+        result.attribTypes = ExtendedAttributeType.executeQuery(attribTypesQ.query, attribTypesQ.namedParams)
+
+        // A useful list of assets without subItems to be given to the user.
+        def assetsWithoutEquipmentQ = new HqlBuilder().query {
+            select 'distinct asset'
+            from 'Asset asset',
+                    'left join asset.assetSubItems as assetSubItem'
+            where 'assetSubItem = null'
+                namedParams.section = result.section
+                and 'asset.section = :section'
+        }
+        result.assetsWithoutEquipment = Asset.executeQuery(assetsWithoutEquipmentQ.query, assetsWithoutEquipmentQ.namedParams)
+
+        // Subquery to count regulatory tasks.
+        def regulatoryTaskCountQ = new HqlBuilder().query {
+
+            select 'count (distinct task)'
+            from 'Task as task',
+                    'left join task.associatedAssets as associatedAsset'
+            where 'task.regulatoryRequirement = true'
+                and 'task.targetStartDate < :endDate'
+                and 'task.targetCompletionDate >= :startDate'
+                and '(task.primaryAsset.id = asset.id or associatedAsset.id = asset.id)'
+                and 'task.trash = false'
+        }
+
+        def totalRegulatoryTaskCountQ = regulatoryTaskCountQ.query
+
+        regulatoryTaskCountQ.and 'task.taskStatus.id = 3'
+        def completedRegulatoryTaskCountQ = regulatoryTaskCountQ.query
+
+        // A result is returned for every level 1 assetSubItem and for any extended attributes.
+        def q = new HqlBuilder().query {
+
+            select 'new map(asset.name as assetName',
+                        'assetSubItem.name as name',
+                        'assetSubItem.description as description',
+                        'assetSubItem.comment as comment',
+                        "0 as totalRegulatoryTaskCount",
+                        "0 as completedRegulatoryTaskCount",
+                        'attribT.name as attribType',
+                        'attrib.value as attribValue)'
+            from 'AssetSubItem assetSubItem',
+                    'inner join assetSubItem.assets as asset',
+                    'left join assetSubItem.assetSubItemExtendedAttributes as attrib',
+                    'left join attrib.extendedAttributeType as attribT'
+            where 'asset != null' // ensure that only level 1 assetSubItems are returned.
+                namedParams.section = result.section
+                and 'asset.section = :section'
+            order 'by asset.name asc, assetSubItem.name asc, attribT.name asc'
+        }
+        def equipmentResults = AssetSubItem.executeQuery(q.query, q.namedParams)
+
+        // A result is returned for every asset and for any extended attributes.
+        def assetResultsQ = new HqlBuilder().query {
+
+            // Subquery namedParams.
+            namedParams.startDate = result.startDate
+            namedParams.endDate = result.endDate+1
+
+            select 'new map(asset.name as assetName',
+                        "'   Asset Details' as name", // Place holder 'equipment' name, 3 leading spaces for sorting.
+                        'asset.description as description',
+                        'asset.comment as comment',
+                        "($totalRegulatoryTaskCountQ) as totalRegulatoryTaskCount",
+                        "($completedRegulatoryTaskCountQ) as completedRegulatoryTaskCount",
+                        'attribT.name as attribType',
+                        'attrib.value as attribValue)'
+            from 'Asset asset',
+                    'left join asset.assetExtendedAttributes as attrib',
+                    'left join attrib.extendedAttributeType as attribT'
+            where 'asset.section = :section'
+                    namedParams.section = result.section
+            order 'by asset.name asc, attribT.name asc'
+        }
+        def assetResults = Asset.executeQuery(assetResultsQ.query, assetResultsQ.namedParams)
+
+        // Add asset details to equipmentResults.
+        equipmentResults.addAll(assetResults)
+        equipmentResults.sort { p1, p2 -> p1.assetName.compareToIgnoreCase(p2.assetName) ?: p1.name.compareToIgnoreCase(p2.name) }
+
+        // Build the report table rows.
+        // Rows are keyed by equipmentResult.assetName+equipmentResult.name` while the value is a Map of the attributes.
+        // The report table then groups by assetName.
+        def rows = [:]
+        equipmentResults.each { equipmentResult ->
+
+            def rowKey = equipmentResult.assetName+equipmentResult.name
+
+            // Create new row if it does not exist yet.
+            if(!rows.containsKey(rowKey)) {
+                rows[rowKey] = ['assetName': equipmentResult.assetName,
+                                            'name':equipmentResult.name,
+                                            'description':equipmentResult.description,
+                                            'comment':equipmentResult.comment,
+                                            'Regulatory Task Completion': ' ']
+
+                // Add all attribType columns.
+                result.attribTypes.each { column ->
+                    rows[rowKey][column] = ' '
+                }
+
+                // Caluculate and assign RegulatoryTaskCompletion, only for Assets.
+                if(params.calculateRegulatoryTaskCompletion) {
+
+                    if(equipmentResult.totalRegulatoryTaskCount) {
+                        def percentComplete = (equipmentResult.completedRegulatoryTaskCount / equipmentResult.totalRegulatoryTaskCount)*100
+                        rows[rowKey]['Regulatory Task Completion'] = "${percentComplete.toInteger()}% (${equipmentResult.completedRegulatoryTaskCount}/${equipmentResult.totalRegulatoryTaskCount})"
+                    }
+                    else if(equipmentResult.name == '   Asset Details')
+                        rows[rowKey]['Regulatory Task Completion'] = 'N/A'
+                }
+
+            } // Create new row.
+
+            // Assign value to column.
+            rows[rowKey][equipmentResult.attribType] = equipmentResult.attribValue
+        } // each.
+
+        // The value of each row is the dataList used by the report table.
+        result.dataList = rows.collect {it.value}
+        // Print formatting, since we are done with these as objects.
+        result.attribTypes = result.attribTypes.join(', ')
+        result.assetsWithoutEquipment = result.assetsWithoutEquipment.collect {it.name}.join(', ')
+
+        // Success.
+        return result
+
+    } // getEquipmentRegister
+
+    /**
+    * Selects and returns assets regulatory requirements as specified in recurring regulatory tasks.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getRegulatoryRequirements(params, locale) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: [] ]
+            return result
+        }
+
+        result.section = Section.get(params.section.id.toLong())
+        result.site = result.section.site
+
+        result.startDate = params.startDate ?: dateUtilService.oneWeekAgo
+        result.endDate = params.endDate ?: dateUtilService.today
+        // Auto swap date range.
+        if(result.startDate > result.endDate) {
+            def tempStartDate = result.startDate
+            result.startDate = result.endDate
+            result.endDate = tempStartDate
+        }
+
+        result.startDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startDate)
+        result.endDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.endDate)
+
+        result.summary = "This report only selects primary assets and not associated assets. \n"
+        result.summary += "Tasks must have recurrence enabled and regulatory requirement set."
+
+        // Subquery to count subTasks..
+        def subTaskQ = new HqlBuilder().query {
+            select 'count(subTask)'
+            from 'task.subTasks as subTask'
+            where 'subTask.trash = false'
+                and 'subTask.targetStartDate < :endDate'
+                and 'subTask.targetCompletionDate >= :startDate'
+        }
+        def subTaskTotalQ = subTaskQ.query
+
+        subTaskQ.and 'subTask.taskStatus.id = 3' // Complete.
+        def subTaskCompletedQ = subTaskQ.query
+
+        def regulatoryTaskQ = new HqlBuilder().query {
+            select 'new map(primaryAsset.name as assetName',
+                        'primaryAsset.description as assetDescription',
+                        'primaryAsset.isActive as assetIsActive',
+                        'task.id as taskId',
+                        'task.description as taskDescription',
+                        "($subTaskTotalQ) as subTaskTotalCount",
+                        "($subTaskCompletedQ) as subTaskCompletedCount)"
+                        namedParams.startDate = result.startDate
+                        namedParams.endDate = result.endDate
+            from 'Task task',
+                    'left join task.primaryAsset as primaryAsset',
+                    'left join task.taskRecurringSchedule as taskRecurringSchedule'
+            where 'task.regulatoryRequirement = true'
+                and 'taskRecurringSchedule.enabled = true'
+                and 'task.trash = false'
+                        namedParams.sectionId = result.section.id
+                and 'primaryAsset.section.id = :sectionId'
+        }
+        result.tasks = Task.executeQuery(regulatoryTaskQ.query, regulatoryTaskQ.namedParams)
+
+        // Build the report table row for each task.
+        result.tasks.each { task ->
+
+            // Caluculate percentages and build description.
+            def percentComplete
+            def completionFigures
+            if(task.subTaskTotalCount) {
+                percentComplete = (task.subTaskCompletedCount / task.subTaskTotalCount) * 100
+                task.completionFigures = "${percentComplete.toInteger()}% ($task.subTaskCompletedCount/$task.subTaskTotalCount)"
+            }
+            else
+                task.completionFigures = '0 sub tasks in date range'
+        } // tasks.each
+
+        result.dataList = result.tasks
+        result.dataList.sort { p1, p2 -> p1.assetName.compareToIgnoreCase(p2.assetName) }
+
+        // Success.
+        return result
+
+    } // getRegulatoryRequirements
+
+    /**
+    * Selects and returns assets mandatory requirements as specified in recurring mandatory tasks.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getMandatoryRequirements(params, locale) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: [] ]
+            return result
+        }
+
+        result.section = Section.get(params.section.id.toLong())
+        result.site = result.section.site
+
+        result.startDate = params.startDate ?: dateUtilService.oneWeekAgo
+        result.endDate = params.endDate ?: dateUtilService.today
+        // Auto swap date range.
+        if(result.startDate > result.endDate) {
+            def tempStartDate = result.startDate
+            result.startDate = result.endDate
+            result.endDate = tempStartDate
+        }
+
+        result.startDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startDate)
+        result.endDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.endDate)
+
+        result.summary = "This report only selects primary assets and not associated assets. \n"
+        result.summary += "Tasks must have recurrence enabled and mandatory requirement set."
+
+        // Subquery to count subTasks..
+        def subTaskQ = new HqlBuilder().query {
+            select 'count(subTask)'
+            from 'task.subTasks as subTask'
+            where 'subTask.trash = false'
+                and 'subTask.targetStartDate < :endDate'
+                and 'subTask.targetCompletionDate >= :startDate'
+        }
+        def subTaskTotalQ = subTaskQ.query
+
+        subTaskQ.and 'subTask.taskStatus.id = 3' // Complete.
+        def subTaskCompletedQ = subTaskQ.query
+
+        def mandatoryTaskQ = new HqlBuilder().query {
+            select 'new map(primaryAsset.name as assetName',
+                        'primaryAsset.description as assetDescription',
+                        'primaryAsset.isActive as assetIsActive',
+                        'task.id as taskId',
+                        'task.description as taskDescription',
+                        "($subTaskTotalQ) as subTaskTotalCount",
+                        "($subTaskCompletedQ) as subTaskCompletedCount)"
+                        namedParams.startDate = result.startDate
+                        namedParams.endDate = result.endDate
+            from 'Task task',
+                    'left join task.primaryAsset as primaryAsset',
+                    'left join task.taskRecurringSchedule as taskRecurringSchedule'
+            where 'task.mandatoryRequirement = true'
+                and 'taskRecurringSchedule.enabled = true'
+                and 'task.trash = false'
+                        namedParams.sectionId = result.section.id
+                and 'primaryAsset.section.id = :sectionId'
+        }
+        result.tasks = Task.executeQuery(mandatoryTaskQ.query, mandatoryTaskQ.namedParams)
+
+        // Build the report table row for each task.
+        result.tasks.each { task ->
+
+            // Caluculate percentages and build description.
+            def percentComplete
+            def completionFigures
+            if(task.subTaskTotalCount) {
+                percentComplete = (task.subTaskCompletedCount / task.subTaskTotalCount) * 100
+                task.completionFigures = "${percentComplete.toInteger()}% ($task.subTaskCompletedCount/$task.subTaskTotalCount)"
+            }
+            else
+                task.completionFigures = '0 sub tasks in date range'
+        } // tasks.each
+
+        result.dataList = result.tasks
+        result.dataList.sort { p1, p2 -> p1.assetName.compareToIgnoreCase(p2.assetName) }
+
+        // Success.
+        return result
+
+    } // getMandatoryRequirements
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/AssetService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AssetService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AssetService.groovy	(revision 875)
@@ -0,0 +1,377 @@
+
+import org.apache.commons.lang.WordUtils
+
+class AssetService {
+
+    boolean transactional = false
+
+    def sessionFactory
+
+    def assetSubItemService
+
+    /**
+    * Determines and returns a possible list of asset sub items.
+    * @returns A list of the possible assetSubItems.
+    */
+    def possibleAssetSubItems() {
+        def criteria = AssetSubItem.createCriteria()
+        def possibleAssetSubItems = criteria.list() {
+            and {
+                eq('isActive', true)
+                isNull("parentItem")
+                }
+        }
+    }
+
+    /**
+    * Determines and returns a list of assemblies for an asset.
+    * This is purely a 'load from database' type method since a new hibernateSession is used.
+    * @params Asset to get the subItems for.
+    * @returns A list of the assemblies.
+    */
+    def getAssemblies(asset) {
+        def assemblies = []
+        if(!(asset instanceof Asset))
+            return assemblies
+        // Database efficiency:
+        // The asset is configured to batch fetch assetSubItems which
+        // in turn are configured to batch fetch subItems.
+        Asset.withNewSession {
+            Asset.get(asset.id).assetSubItems.each {
+                assemblies.addAll(it.subItems)
+            }
+        }
+        assemblies.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+        return assemblies
+    }
+
+    def delete(params) {
+        Asset.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assetInstance && m.field)
+                    result.assetInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Asset", params.id] ]
+                return result
+            }
+
+            result.assetInstance = Asset.get(params.id)
+
+            if(!result.assetInstance)
+                return fail(code:"default.not.found")
+
+            if(result.assetInstance.maintenanceActions)
+                return fail(code:"maintenanceActions.still.associated")
+
+            // Remove orphan assetSubItems.
+            def assetSubItems = new ArrayList(result.assetInstance.assetSubItems) // avoid ConcurrentModificationException.
+            def r
+            for(assetSubItem in assetSubItems) {
+                result.assetInstance.removeFromAssetSubItems(assetSubItem)
+                if(!assetSubItem.assets && !assetSubItem.parentItem) {
+                    r = assetSubItemService.delete(id: assetSubItem.id)
+                    if(r.error) {
+                        log.debug r.error
+                        fail(code:"asset.subItems.delete.failure")
+                        break
+                    }
+                }
+            }
+
+            if(result.error)
+                return result
+
+            // Success.
+            // We have handled all the foreign keys so the delete should go forward.
+            // Can't flush here due to cascading from Section and Site.
+            // And without flush there is no point it trying to catch the dao.DataIntegrityViolationException
+            // since that will only happen after leaving the transaction.
+            result.assetInstance.delete()
+            return result
+
+        } // end withTransaction
+    } // end delete()
+
+    def create(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["Asset", params.id] ]
+            return result
+        }
+
+        result.assetInstance = new Asset()
+        result.assetInstance.properties = params
+
+        // success
+        return result
+    }
+
+    def copy(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["Asset", params.id] ]
+            return result
+        }
+
+        result.assetToCopy = Asset.get(params.assetToCopy?.id)
+
+        if(!result.assetToCopy)
+            return fail(code: "asset.copy.asset.required")
+
+        result.assetInstance = new Asset(name: result.assetToCopy.name,
+                                                            description: result.assetToCopy.description,
+                                                            comment: result.assetToCopy.comment,
+                                                            section: result.assetToCopy.section)
+
+        result.assetInstance.properties = params
+
+        // success
+        return result
+    }
+
+    def save(params) {
+        def result = [:]
+        def fail = { Map m ->
+            if(result.assetInstance && m.field) 
+                result.assetInstance.errors.rejectValue(m.field, m.code)
+            result.error = [ code: m.code, args: ["Asset", params.id] ]
+            return result
+        }
+
+        result.assetInstance = new Asset(params)
+
+        use(WordUtils) {
+            result.assetInstance.name = result.assetInstance.name.capitalize()
+            result.assetInstance.description = result.assetInstance.description.capitalize()
+        }
+
+        if(result.assetInstance.hasErrors() || !result.assetInstance.save(flush: true))
+            return fail(code:"default.create.failure")
+
+        // success
+        return result
+    }
+
+    def saveCopy(params) {
+        Asset.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assetInstance && m.field)
+                    result.assetInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Asset", params.id] ]
+                return result
+            }
+
+            result.assetToCopy = Asset.get(params.assetToCopy?.id)
+            if(!result.assetToCopy)
+                return fail(code:"default.not.found")
+
+            if(!params.copyMethod)
+                fail(code:"asset.copy.method.required")
+
+            result.assetInstance =  new Asset(params)
+
+            if(result.assetInstance.hasErrors() || !result.assetInstance.save())
+                return fail(code:"default.create.failure")
+
+            def assetSubItemInstance1
+
+            // Copy subItems from level 2 and bellow.
+            def copyAssetSubItem = { assetSubItemToCopy, parentItem ->
+                def nextCount = AssetSubItem.count() + 1
+                def baseName = assetSubItemToCopy.name.split('\\(id:')[0]
+                def name = baseName +'(id:'+nextCount+')'
+                def assetSubItemInstance = new AssetSubItem(name: name,
+                                                                                            description: assetSubItemToCopy.description,
+                                                                                            parentItem: parentItem)
+
+                if(assetSubItemInstance.hasErrors() || !assetSubItemInstance.save())
+                    return fail(code:"asset.copy.subItem.create.failure")
+
+                def i = 0
+                for(assetSubItem in assetSubItemToCopy.subItems) {
+                    call(assetSubItem, assetSubItemInstance)
+                    // Protect against endless recurrsion.
+                    i++
+                    if(i > 100)
+                        fail(code:"asset.copy.subItem.too.many.failure")
+                    // Stop if an error is flagged.
+                    if(result.error)
+                        break
+                }
+            } //copyAssetSubItem
+
+            // Copy the 1st level of subItems.
+            def copyAssetSubItem1 = { assetSubItemToCopy ->
+                def nextCount = AssetSubItem.count() + 1
+                def baseName = assetSubItemToCopy.name.split('\\(id:')[0]
+                def name = baseName +'(id:'+nextCount+')'
+                assetSubItemInstance1 = new AssetSubItem(name: name,
+                                                                                        description: assetSubItemToCopy.description,
+                                                                                        asset: result.assetInstance)
+
+                if(assetSubItemInstance1.hasErrors() || !assetSubItemInstance1.save())
+                    return fail(code:"asset.copy.subItem.create.failure")
+
+                result.assetInstance.addToAssetSubItems(assetSubItemInstance1)
+
+                def i = 0
+                for(assetSubItem in assetSubItemToCopy.subItems) {
+                    copyAssetSubItem(assetSubItem, assetSubItemInstance1)
+                    // Protect against endless recurrsion.
+                    i++
+                    if(i > 100)
+                        fail(code:"asset.copy.subItem.too.many.failure")
+                    // Stop if an error is flagged.
+                    if(result.error)
+                        break
+                }
+            } //copyAssetSubItem1
+
+            def linkAssetSubItem = { assetSubItemToLink ->
+                result.assetInstance.addToAssetSubItems(assetSubItemToLink)
+            }
+
+            def i = 0
+            for(assetSubItem in result.assetToCopy.assetSubItems) {
+
+                if(params.copyMethod == "copy")
+                    copyAssetSubItem1(assetSubItem)
+                else
+                    linkAssetSubItem(assetSubItem)
+                // Protect against endless recurrsion.
+                i++
+                if(i > 100)
+                    fail(code:"asset.copy.subItem.too.many.failure")
+                // Stop if an error is flagged.
+                if(result.error)
+                    break
+            }
+
+            // Success or not.
+            return result
+
+        } // end withTransaction
+    } // end saveCopySrvce
+
+    /**
+    * Create recommended extended attributes for all assets.
+    */
+    def createRecommendedExtendedAttributes() {
+        def result = [:]
+
+        def hibernateSession = sessionFactory.currentSession
+
+        def assets = Asset.list()
+        def locationDescription = ExtendedAttributeType.findByName("Location Description")
+        def ecr = ExtendedAttributeType.findByName("ecr")
+        def assetNumber = ExtendedAttributeType.findByName("Asset Number")
+        def assetCondition = ExtendedAttributeType.findByName("Asset Condition")
+        def maintenancePercentComplete = ExtendedAttributeType.findByName("Maintenance % Completion")
+        def registrationRequired = ExtendedAttributeType.findByName("Registration Required")
+        def registrationExpiryDate =  ExtendedAttributeType.findByName("Registration Expiry Date")
+        def regulatoryRequirement = ExtendedAttributeType.findByName("Regulatory Requirement")
+        def riskLevel = ExtendedAttributeType.findByName("Risk Level")
+        def safeWorkProcedure = ExtendedAttributeType.findByName("Safe Work Procedure")
+
+        for(asset in assets) {
+
+            def attributeTypes = asset.assetExtendedAttributes.collect {it.extendedAttributeType}
+
+            //AssetExtendedAttribute
+            def assetExtendedAttributeInstance
+
+            if(!attributeTypes.contains(locationDescription)) {
+                //AssetExtendedAttribute #1
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: locationDescription)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(ecr)) {
+                //AssetExtendedAttribute #2
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: ecr)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(assetNumber)) {
+                //AssetExtendedAttribute #3
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: assetNumber)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(assetCondition)) {
+                //AssetExtendedAttribute #4
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: assetCondition)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(maintenancePercentComplete)) {
+                //AssetExtendedAttribute #5
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "TBA",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: maintenancePercentComplete)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(registrationRequired)) {
+                //AssetExtendedAttribute #6
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: registrationRequired)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(registrationExpiryDate)) {
+                //AssetExtendedAttribute #7
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType:registrationExpiryDate)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(regulatoryRequirement)) {
+                //AssetExtendedAttribute #8
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: regulatoryRequirement)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(riskLevel)) {
+                //AssetExtendedAttribute #9
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: riskLevel)
+                assetExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(safeWorkProcedure)) {
+                //AssetExtendedAttribute #10
+                assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Not Specified",
+                                                                                                                    asset: asset,
+                                                                                                                    extendedAttributeType: safeWorkProcedure)
+                assetExtendedAttributeInstance.save()
+            }
+
+            hibernateSession.flush()
+
+        } // for
+
+        // Success.
+        return result
+
+    } // createRecommendedExtendedAttributes()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/AssetSubItemService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AssetSubItemService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AssetSubItemService.groovy	(revision 875)
@@ -0,0 +1,205 @@
+
+import net.kromhouts.HqlBuilder
+import org.apache.commons.lang.WordUtils
+
+class AssetSubItemService {
+
+    boolean transactional = false
+
+    def sessionFactory
+
+    /**
+    * Determines and returns sorted list of possible parent items.
+    * @param assetSubItemInstance The instance to prepare the list for.
+    * @returns A list of the possible parentItems.
+    */
+    def possibleParentItems(assetSubItemInstance) {
+        def criteria = AssetSubItem.createCriteria()
+        def possibleParentItems = criteria.list() {
+            and {
+                eq('isActive', true)
+                ne('id', assetSubItemInstance.id)
+                assetSubItemInstance.subItems.each() { notEqual('id', it.id) }
+                }
+        }
+        possibleParentItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+    }
+
+    def delete(params) {
+        AssetSubItem.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assetSubItemInstance && m.field)
+                    result.assetSubItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssetSubItem", params.id] ]
+                return result
+            }
+
+            result.assetSubItemInstance = AssetSubItem.get(params.id)
+
+            if(!result.assetSubItemInstance)
+                return fail(code:"default.not.found")
+
+            for(subItem in result.assetSubItemInstance.subItems) {
+                if(subItem.maintenanceActions)
+                    fail(code:"maintenanceActions.still.associated.subItem")
+            }
+
+            if(result.error)
+                return result
+
+            if(result.assetSubItemInstance.maintenanceActions)
+                return fail(code:"maintenanceActions.still.associated")
+
+            if(result.assetSubItemInstance.assets)
+                return fail(code:"assetSubItem.assets.associated")
+
+            // We have handled all the foreign keys so the delete should go forward.
+            // Can't flush here due to cascading from Section and Site.
+            // And without flush there is no point it trying to catch the dao.DataIntegrityViolationException
+            // since that will only happen after leaving the transaction.
+            result.assetSubItemInstance.delete()
+            return result //Success.
+
+        } // withTransaction
+    }
+
+    def create(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["AssetSubItem", params.id] ]
+            return result
+        }
+
+        result.assetSubItemInstance = new AssetSubItem()
+        result.assetSubItemInstance.properties = params
+
+        // pass in an asset to link to if provided.
+        if(params.asset?.id)
+            result.assetInstance = Asset.get(params.asset.id)
+
+        // success
+        return result
+    }
+
+    def save(params) {
+        AssetSubItem.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assetSubItemInstance && m.field)
+                    result.assetSubItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssetSubItem", params.id] ]
+                return result
+            }
+
+            result.assetSubItemInstance = new AssetSubItem(params)
+
+            use(WordUtils) {
+                result.assetSubItemInstance.name = result.assetSubItemInstance.name.capitalize()
+                result.assetSubItemInstance.description = result.assetSubItemInstance.description.capitalize()
+            }
+
+            if(params.asset?.id) {
+                result.assetInstance = Asset.get(params.asset.id)
+
+                if(!result.assetInstance)
+                    return fail(code:"assetSubItem.asset.not.found")
+            }
+
+            if(result.assetSubItemInstance.hasErrors() || !result.assetSubItemInstance.save(flush: true))
+                return fail(code:"default.create.failure")
+
+            if(result.assetInstance)
+                result.assetInstance.addToAssetSubItems(result.assetSubItemInstance)
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    } // save()
+
+    /**
+    * Get a list of level 1 assetSubItems.
+    * @returns By default all level 1 assetSubItems are returned.
+    */
+    def getLevel1AssetSubItems(params) {
+
+        // A result is returned for every level 1 assetSubItem.
+        def q = new HqlBuilder().query {
+            select 'assetSubItem'
+            from 'AssetSubItem assetSubItem',
+                    'inner join assetSubItem.assets as asset'
+            where 'asset != null' // ensure that only level 1 assetSubItems are returned.
+        }
+        def assetSubItems = AssetSubItem.executeQuery(q.query, q.namedParams)
+
+    }
+
+    /**
+    * Create recommended extended attributes for all level 1 subItems.
+    */
+    def createRecommendedExtendedAttributes() {
+        def result = [:]
+
+        def hibernateSession = sessionFactory.currentSession
+
+        def assetSubItems = getLevel1AssetSubItems()
+
+        def manufacturer = ExtendedAttributeType.findByName("Manufacturer")
+        def modelNumber = ExtendedAttributeType.findByName("Model Number")
+        def serialNumber = ExtendedAttributeType.findByName("Serial Number")
+        def manufacturedDate = ExtendedAttributeType.findByName("Manufactured Date")
+
+        for(assetSubItem in assetSubItems) {
+
+            def attributeTypes = assetSubItem.assetSubItemExtendedAttributes.collect {it.extendedAttributeType}
+
+            //AssetSubItemExtendedAttribute
+            def assetSubItemExtendedAttributeInstance
+
+            if(!attributeTypes.contains(manufacturer)) {
+                //AssetSubItemExtendedAttribute #1
+                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
+                                                                                                                    assetSubItem: assetSubItem,
+                                                                                                                    extendedAttributeType: manufacturer)
+                assetSubItemExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(modelNumber)) {
+                //AssetSubItemExtendedAttribute #2
+                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
+                                                                                                                    assetSubItem: assetSubItem,
+                                                                                                                    extendedAttributeType: modelNumber)
+                assetSubItemExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(serialNumber)) {
+                //AssetSubItemExtendedAttribute #3
+                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
+                                                                                                                    assetSubItem: assetSubItem,
+                                                                                                                    extendedAttributeType: serialNumber)
+                assetSubItemExtendedAttributeInstance.save()
+            }
+
+            if(!attributeTypes.contains(manufacturedDate)) {
+                //AssetSubItemExtendedAttribute #4
+                assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Not Specified",
+                                                                                                                    assetSubItem: assetSubItem,
+                                                                                                                    extendedAttributeType: manufacturedDate)
+                assetSubItemExtendedAttributeInstance.save()
+            }
+
+            hibernateSession.flush()
+
+        } // for
+
+        // Success.
+        return result
+
+    } // createRecommendedExtendedAttributes()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/AssetTreeService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AssetTreeService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AssetTreeService.groovy	(revision 875)
@@ -0,0 +1,525 @@
+class AssetTreeService {
+
+    boolean transactional = false
+
+    def js = new JsUtilService()
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    /** General */
+    def nameDescriptionSeperator = ' -- '
+
+    /** Html class and id settings */
+    def buttonHtmlClass = 'tree_button'
+    def paneHtmlClass = 'overlayPane'
+    def paneHtmlId = 'assetTreePane'
+    def paneCloseHtmlClass = 'pane_close'
+    def tableDivHtmlClass = 'tree'
+    def tableHtmlId = 'assetTreeTable'
+    def tableLoadingImgId = 'assetTreeLoadingImg'
+
+    /** Imgs */
+    def treeRootImg = ''
+    def addImg = ''
+    def copyImg = ''
+    def bulletTreePlusImg = ''
+    def bulletTreeMinusImg = ''
+    def dashImg = ''
+    def closeImg = ''
+
+    /** Urls */
+    def assetTreeActionUrl = ''
+    def saveAssetTreeStatusActionUrl = ''
+
+    /** Links */
+    def siteCreateBaseLink = ''
+    def siteShowBaseLink = ''
+    def siteEditBaseLink = ''
+    def sectionCreateBaseLink = ''
+    def sectionShowBaseLink = ''
+    def sectionEditBaseLink = ''
+    def assetCreateBaseLink = ''
+    def assetShowBaseLink = ''
+    def assetEditBaseLink = ''
+    def assetCopyBaseLink = ''
+    def assetSubItemCreateBaseLink = ''
+    def assetSubItemCreateWithParentBaseLink = ''
+    def assetSubItemShowBaseLink = ''
+    def assetSubItemEditBaseLink = ''
+
+    /**
+    * Initialise some class wide variables.
+    * This has been done to optimise since g.link and g.resource calls are expensive.
+    * This can't be done by class construction since some of the metaclass stuff is not available yet, e.g. 'out' etc.
+    * Initialise can't be called from BootStrap.
+    */
+    def initialise() {
+        log.debug "Initialise asset tree variables."
+
+        // Imgs.
+        treeRootImg = g.resource(dir:'images/skin',file:'chart_organisation.png')
+        addImg = g.resource(dir:'images/skin',file:'database_add.png')
+        copyImg = g.resource(dir:'images/skin',file:'page_copy.png')
+        bulletTreePlusImg = g.resource(dir:'images/skin',file:'bullet_tree_plus.png')
+        bulletTreeMinusImg = g.resource(dir:'images/skin',file:'bullet_tree_minus.png')
+        dashImg = g.resource(dir:'images/skin',file:'hline_short.png')
+        closeImg = g.resource(dir:'images/skin',file:'cross.png')
+
+        // Urls.
+        assetTreeActionUrl = g.createLink(controller: 'assetDetailed', action: 'assetTree')
+        saveAssetTreeStatusActionUrl = g.createLink(controller: 'assetDetailed', action: 'saveAssetTreeStatus')
+
+        // Links
+        siteCreateBaseLink = g.createLink(controller: 'siteDetailed', action: 'create').toString()
+        siteShowBaseLink = g.createLink(controller: 'siteDetailed', action: 'show').toString()
+        siteEditBaseLink = g.createLink(controller: 'siteDetailed', action: 'edit').toString()
+        sectionCreateBaseLink = g.createLink(controller: 'sectionDetailed', action: 'create').toString()
+        sectionShowBaseLink = g.createLink(controller: 'sectionDetailed', action: 'show').toString()
+        sectionEditBaseLink = g.createLink(controller: 'sectionDetailed', action: 'edit').toString()
+        assetCreateBaseLink = g.createLink(controller: 'assetDetailed', action: 'create').toString()
+        assetShowBaseLink = g.createLink(controller: 'assetDetailed', action: 'show').toString()
+        assetEditBaseLink = g.createLink(controller: 'assetDetailed', action: 'edit').toString()
+        assetCopyBaseLink = g.createLink(controller: 'assetDetailed', action: 'copy').toString()
+        assetSubItemCreateBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'create').toString()
+        assetSubItemCreateWithParentBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'create').toString()
+        assetSubItemShowBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'show').toString()
+        assetSubItemEditBaseLink = g.createLink(controller: 'assetSubItemDetailed', action: 'edit').toString()
+        // Success.
+        return true
+    }
+
+    /** Name and Description Formatting */
+
+    def name(obj) {
+        obj.name.encodeAsHTML()
+    }
+
+    def description(obj) {
+        def s =  obj.description.encodeAsHTML()
+        s = s? (nameDescriptionSeperator + s) : ''
+    }
+
+    /**
+    * Build and return the asset tree button.
+    * Built here instead of directly in the taglib since we may need to initialise.
+    */
+    def buildAssetTreeButton(attrs) {
+
+        // Self initialisation ;-)
+        if(!treeRootImg)
+            initialise()
+
+        def sw = new StringWriter()
+        def mkp = new groovy.xml.MarkupBuilder(sw)
+
+        mkp.div(class: buttonHtmlClass) {
+            a( href: hrefShowPane() ) {
+                img(src: treeRootImg, alt: 'Asset Tree', title: 'Asset Tree')
+            }
+        } // mkp
+
+        return sw.toString()
+    }
+
+    /**
+    * Build and return the empty asset tree pane, ready for populating by ajax call to buildAssetTree.
+    * Built here instead of directly in the taglib since we may need to initialise.
+    */
+    def buildAssetTreePane(attrs) {
+
+        // Self initialisation ;-)
+        if(!treeRootImg)
+            initialise()
+
+        def sw = new StringWriter()
+        def mkp = new groovy.xml.MarkupBuilder(sw)
+
+        mkp.div(class: paneHtmlClass, id: paneHtmlId, style: 'display:none;') {
+            div(class: paneCloseHtmlClass) {
+                a( href: js.toggle(paneHtmlId) ) {
+                    img(src: closeImg)
+                }
+            }
+
+            div(class: tableDivHtmlClass) {
+                table(id: tableHtmlId) {
+                    tr() {
+                        td(valign: 'top', class: 'value') {
+                            ul() {
+                                img(src: treeRootImg, id: tableLoadingImgId, alt: 'TreeRoot')
+                                li() {
+                                } // li
+                            } // ul
+                        } // td
+                    } // tr
+                } // table
+            } // div
+        } // mkp
+
+        return sw.toString()
+
+    } // buildAssetPane
+
+    /**
+    * Build and return the asset tree table.
+    * To be used in conjunction with AssetTreeTagLib which inserts the wrapper div built by buildAssetTreePane().
+    * This table replaces the contents of the wrapper div.
+    * @returns The asset tree table as a String
+    */
+    def buildAssetTree(params, session) {
+
+        def startedAt = System.currentTimeMillis()
+
+        // Self initialisation ;-)
+        if(!treeRootImg)
+            initialise()
+
+        def sites = Site.withCriteria {
+            eq("isActive", true)
+        }
+
+        def visibleBranches = session.assetTreeVisibleBranches ? session.assetTreeVisibleBranches.tokenize(',') : []
+
+        def branchStyle = { branchId ->
+            if(visibleBranches.contains(branchId))
+                ''
+            else
+                'display:none;'
+        }
+
+        def branchImg = { branchId ->
+            if(visibleBranches.contains(branchId))
+                bulletTreeMinusImg
+            else
+                bulletTreePlusImg
+        }
+
+        def divIdCount = 0
+        def divId = ''
+        def nextDivId = {
+            divIdCount++
+            divId = 'assetTreeBranch'+divIdCount
+        }
+
+        def sw = new StringWriter()
+        def mkp = new groovy.xml.MarkupBuilder(sw)
+
+        // Offer a site create link if no sites are found.
+        if(!sites) {
+            mkp.div(class: tableDivHtmlClass) {
+
+                div(class: paneCloseHtmlClass) {
+                    a( href: js.toggle(paneHtmlId) ) {
+                        img(src: closeImg)
+                    }
+                }
+
+                table(id: tableHtmlId) {
+                    tr() {
+                        td( valign: 'top', class: 'value') {
+                            ul() {
+                                img(src: treeRootImg, alt: 'TreeRoot')
+                                li() {
+                                    a(href: siteCreateBaseLink) {
+                                        img(src: addImg, alt: 'Add', title: 'Add Site')
+                                    }
+                                } // li
+                            } // ul
+                        } // td
+                    } // tr
+                } // table
+
+                div( class: 'buttons') {
+                    span(class: 'button') {
+                        input( type: 'button', value: g.message(code: 'default.close.text'), onclick: js.toggle(paneHtmlId, "onclick") )
+                    }
+                } // button div
+            } // mkp
+            return sw.toString()
+        } // if(!sites)
+
+
+        // The main populated table.
+        /// @todo: use a loop for the subItem levels.
+        mkp.div(class: tableDivHtmlClass) {
+
+            div(class: paneCloseHtmlClass) {
+                a( href: hrefHideAndSavePane() ) {
+                    img(src: closeImg)
+                }
+            }
+
+            table(id: tableHtmlId) {
+                tr() {
+                    td(valign: 'top', class: 'value') {
+                        ul() {
+                            img(src: treeRootImg, alt: 'TreeRoot')
+                            for(site in sites.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                li() {
+                                    if(site.sections) {
+                                        a(href: toggleBranch(nextDivId()) ) {
+                                            img( src: branchImg(divId), id: divId+'img' )
+                                        }
+                                    }
+                                    else
+                                        img(src: dashImg)
+                                    a( href: siteShowLink(site.id), onclick: onclickHideAndSavePane() ) {
+                                        yieldUnescaped( name(site)  )
+                                    }
+                                    yieldUnescaped( description(site)  )
+                                    a(href: sectionCreateLink(site.id), onclick: onclickHideAndSavePane()) {
+                                        img(src: addImg, alt: 'Add', title: 'Add Section')
+                                    }
+                                }
+                                if(site.sections) {
+                                    div( id: divId, style: branchStyle(divId) ) {
+                                        ul() {
+                                            for(section in site.sections.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                li() {
+                                                    if(section.assets) {
+                                                        a( href: toggleBranch(nextDivId()) ) {
+                                                            img(src: branchImg(divId), id: divId+'img' )
+                                                        }
+                                                    }
+                                                    else
+                                                        img(src: dashImg)
+                                                    a( href: sectionShowLink(section.id), onclick: onclickHideAndSavePane() ) {
+                                                        yieldUnescaped( name(section) )
+                                                    }
+                                                    yieldUnescaped( description(section)  )
+                                                    a(href: assetCreateLink(section.id), onclick: onclickHideAndSavePane()) {
+                                                        img(src: addImg, alt: 'Add', title: 'Add Asset')
+                                                    }
+                                                }
+
+                                                if(section.assets) {
+                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                        ul() {
+                                                            for(asset in section.assets.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                li() {
+                                                                    if(asset.assetSubItems) {
+                                                                        a( href: toggleBranch(nextDivId()) ) {
+                                                                            img(src: branchImg(divId), id: divId+'img' )
+                                                                        }
+                                                                    }
+                                                                    else
+                                                                        img(src: dashImg)
+                                                                    a( href: assetShowLink(asset.id), onclick: onclickHideAndSavePane() ) {
+                                                                        yieldUnescaped( name(asset) )
+                                                                    }
+                                                                    yieldUnescaped( description(asset) )
+                                                                    a(href: assetSubItemCreateLink(asset.id), onclick: onclickHideAndSavePane()) {
+                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
+                                                                    }
+                                                                    a(href: assetCopyLink(asset.id), onclick: onclickHideAndSavePane()) {
+                                                                        img(src: copyImg, alt: 'Add', title: 'Copy Asset')
+                                                                    }
+                                                                } // li
+
+                                                                if(asset.assetSubItems) {
+                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                        ul() {
+                                                                            for(assetSubItemL1 in asset.assetSubItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                li() {
+                                                                                    if(assetSubItemL1.subItems) {
+                                                                                        a( href: toggleBranch(nextDivId()) ) {
+                                                                                            img(src: branchImg(divId), id: divId+'img' )
+                                                                                        }
+                                                                                    }
+                                                                                    else
+                                                                                        img(src: dashImg)
+                                                                                    a( href: assetSubItemShowLink(assetSubItemL1.id), onclick: onclickHideAndSavePane() ) {
+                                                                                        yieldUnescaped( name(assetSubItemL1) )
+                                                                                    }
+                                                                                    yieldUnescaped( description(assetSubItemL1) )
+                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL1.id), onclick: onclickHideAndSavePane()) {
+                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
+                                                                                    }
+                                                                                } // li
+
+                                                                                if(assetSubItemL1.subItems) {
+                                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                                        ul() {
+                                                                                            for(assetSubItemL2 in assetSubItemL1.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                                li() {
+                                                                                                    if(assetSubItemL2.subItems) {
+                                                                                                        a( href: toggleBranch(nextDivId()) ) {
+                                                                                                            img( src: branchImg(divId), id: divId+'img' )
+                                                                                                        }
+                                                                                                    }
+                                                                                                    else
+                                                                                                        img(src: dashImg)
+                                                                                                    a( href: assetSubItemShowLink(assetSubItemL2.id), onclick: onclickHideAndSavePane() ) {
+                                                                                                        yieldUnescaped( name(assetSubItemL2) )
+                                                                                                    }
+                                                                                                    yieldUnescaped( description(assetSubItemL2) )
+                                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL2.id), onclick: onclickHideAndSavePane()) {
+                                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
+                                                                                                    }
+                                                                                                } // li
+
+                                                                                                if(assetSubItemL2.subItems) {
+                                                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                                                        ul() {
+                                                                                                            for(assetSubItemL3 in assetSubItemL2.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                                                li() {
+                                                                                                                    if(assetSubItemL3.subItems) {
+                                                                                                                        a( href: toggleBranch(nextDivId()) ) {
+                                                                                                                            img( src: branchImg(divId), id: divId+'img' )
+                                                                                                                        }
+                                                                                                                    }
+                                                                                                                    else
+                                                                                                                        img(src: dashImg)
+                                                                                                                    a( href: assetSubItemShowLink(assetSubItemL3.id), onclick: onclickHideAndSavePane() ) {
+                                                                                                                        yieldUnescaped( name(assetSubItemL3) )
+                                                                                                                    }
+                                                                                                                    yieldUnescaped( description(assetSubItemL3) )
+                                                                                                                    a(href: assetSubItemCreateWithParentLink(assetSubItemL3.id), onclick: onclickHideAndSavePane()) {
+                                                                                                                        img(src: addImg, alt: 'Add', title: 'Add Sub Item')
+                                                                                                                    }
+                                                                                                                } // li
+
+                                                                                                                if(assetSubItemL3.subItems) {
+                                                                                                                    div( id: divId, style: branchStyle(divId) ) {
+                                                                                                                        ul() {
+                                                                                                                            for(assetSubItemL4 in assetSubItemL3.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }) {
+                                                                                                                                li() {
+            //                                                                                                                         if(assetSubItemL4.subItems) {
+            //                                                                                                                             a( href: toggleBranch(nextDivId()) ) {
+            //                                                                                                                                 img( src: branchImg(divId), id: divId+'img' )
+            //                                                                                                                             }
+            //                                                                                                                         }
+            //                                                                                                                         else
+                                                                                                                                    img(src: dashImg)
+                                                                                                                                    a( href: assetSubItemShowLink(assetSubItemL4.id), onclick: onclickHideAndSavePane() ) {
+                                                                                                                                        yieldUnescaped( name(assetSubItemL4) )
+                                                                                                                                    }
+                                                                                                                                    yieldUnescaped( description(assetSubItemL4) )
+            //                                                                                                                         a(href: assetSubItemCreateWithParentLink(assetSubItemL4.id), onclick: onclickHideAndSavePane()) {
+            //                                                                                                                             img(src: addImg, alt: 'Add', title: 'Add Sub Item')
+            //                                                                                                                         }
+                                                                                                                                } // li
+
+                                                                                                                            } // assetSubItemL4
+                                                                                                                        } // ul
+                                                                                                                    } // div
+                                                                                                                } // if(assetSubItemL3.subItems)
+
+
+                                                                                                            } // assetSubItemL3
+                                                                                                        } // ul
+                                                                                                    } // div
+                                                                                                } // if(assetSubItemL2.subItems)
+
+                                                                                            } // assetSubItemL2
+                                                                                        } // ul
+                                                                                    } // div
+                                                                                } // if(assetSubItemL1.subItems)
+
+                                                                            } // assetSubItemL1
+                                                                        } // ul
+                                                                    } // div
+                                                                } // if(asset.assetSubItems)
+
+                                                            } // assets
+                                                        } // ul
+                                                    } // div
+                                                } // if(section.assets)
+
+                                            } //sections
+                                        } // ul
+                                    } // div
+                                } // if(site.sections)
+                            } // sites
+                        } // ul
+                    } // td
+                } // tr
+            } // table
+
+            div( class: 'buttons') {
+                span(class: 'button') {
+                    input( type: 'button', value: g.message(code: 'default.close.text'), onclick: onclickHideAndSavePane() )
+                }
+            }
+
+        } // mkp
+
+        def totalTime = (System.currentTimeMillis() - startedAt)/1000
+        log.debug "Total time to build asset tree: " + totalTime + "sec."
+        return sw.toString()
+
+    } // buildAssetTree
+
+    /** js calls */
+
+    def hrefShowPane() {
+        'javascript: showAssetTreePane(\"assetTreePane\", \"assetTreeLoadingImg' +'\", \"' + assetTreeActionUrl + '\");'
+    }
+
+    def onclickHideAndSavePane() {
+        'return hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");'
+    }
+
+    def hrefHideAndSavePane() {
+        'javascript: hideAssetTreePane(\"assetTreePane\", \"assetTreeTable' + '\", \"' + saveAssetTreeStatusActionUrl + '\");'
+    }
+
+    def toggleBranch(divId) {
+        js.toggleWithImg(divId, divId + 'img', bulletTreeMinusImg, bulletTreePlusImg)
+    }
+
+    /** Links */
+
+    def siteShowLink(id) {
+        siteShowBaseLink + '/' + id
+    }
+
+    def siteEditLink(id) {
+        siteEditBaseLink + '/' + id
+    }
+
+    def sectionCreateLink(siteId) {
+        sectionCreateBaseLink + '?site.id=' + siteId
+    }
+
+    def sectionShowLink(id) {
+        sectionShowBaseLink + '/' + id
+    }
+
+    def sectionEditLink(id) {
+        sectionEditBaseLink + '/' + id
+    }
+
+    def assetCreateLink(sectionId) {
+        assetCreateBaseLink + '?section.id=' + sectionId
+    }
+
+    def assetShowLink(id) {
+        assetShowBaseLink + '/' + id
+    }
+
+    def assetEditLink(id) {
+        assetEditBaseLink + '/' + id
+    }
+
+    def assetCopyLink(id) {
+        assetCopyBaseLink + '?assetToCopy.id=' + id
+    }
+
+    def assetSubItemCreateLink(assetId) {
+        assetSubItemCreateBaseLink + '?asset.id=' + assetId
+    }
+
+    def assetSubItemCreateWithParentLink(parentItemId) {
+        assetSubItemCreateWithParentBaseLink + '?parentItem.id=' + parentItemId
+    }
+
+    def assetSubItemShowLink(id) {
+        assetSubItemShowBaseLink + '/' + id
+    }
+
+    def assetSubItemEditLink(id) {
+        assetSubItemEditBaseLink + '/' + id
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/AssignedGroupService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AssignedGroupService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AssignedGroupService.groovy	(revision 875)
@@ -0,0 +1,209 @@
+import org.hibernate.FetchMode as FM
+
+class AssignedGroupService {
+
+    boolean transactional = false
+
+    def authService
+
+    def delete(params) {
+        AssignedGroup.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assignedGroupInstance && m.field)
+                    result.assignedGroupInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
+                return result
+            }
+
+            result.assignedGroupInstance = AssignedGroup.get(params.id)
+
+            if(!result.assignedGroupInstance)
+                return fail(code:"default.not.found")
+
+            def taskModification = new TaskModification(person: authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(10),
+                                                    task: result.assignedGroupInstance.task)
+
+            if(!taskModification.save())
+                return fail(field:"taskModifications", code:"task.modifications.failedToSave")
+
+            try {
+                result.assignedGroupInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } //end withTransaction
+    } // end delete()
+
+    def edit(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
+            return result
+        }
+
+        result.assignedGroupInstance = AssignedGroup.createCriteria().get {
+            idEq(params.id.toLong())
+            fetchMode("personGroup", FM.EAGER)
+            fetchMode("personGroup.persons", FM.EAGER)
+        }
+
+        if(!result.assignedGroupInstance)
+            return fail(code:"default.not.found")
+
+        result.personGroup = result.assignedGroupInstance.personGroup
+        result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }
+
+        // Success.
+        return result
+    }
+
+    def update(params) {
+        AssignedGroup.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assignedGroupInstance && m.field)
+                    result.assignedGroupInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
+                return result
+            }
+
+            result.personGroup = PersonGroup.createCriteria().get {
+                idEq(params.personGroup.id.toLong())
+                fetchMode("persons", FM.EAGER)
+            }
+
+            // Prevent a null property reference.
+            if(!result.personGroup)
+                return fail(code:"personGroup.not.found")
+
+            result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }
+
+            result.assignedGroupInstance = AssignedGroup.get(params.id)
+
+            if(!result.assignedGroupInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.assignedGroupInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            result.assignedGroupInstance.properties = params
+
+            if(result.assignedGroupInstance.hasErrors() || !result.assignedGroupInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person: authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(10),
+                                                    task: result.assignedGroupInstance.task)
+
+            if(!taskModification.save())
+                return fail(field:"taskModifications", code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end update()
+
+    def create(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
+            return result
+        }
+
+        if(!params.task?.id)
+            fail(code:"assignedGroup.task.not.found")
+
+        result.assignedGroupInstance = new AssignedGroup()
+        result.assignedGroupInstance.properties = params
+
+        result.personGroup = PersonGroup.list().sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }[0] // Get the first result.
+        result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }
+
+        // Success.
+        return result
+    }
+
+    def save(params) {
+        AssignedGroup.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assignedGroupInstance && m.field)
+                    result.assignedGroupInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssignedGroup", params.id] ]
+                return result
+            }
+
+            result.personGroup = PersonGroup.createCriteria().get {
+                idEq(params.personGroup.id.toLong())
+                fetchMode("persons", FM.EAGER)
+            }
+
+            // Prevent a null property reference.
+            if(!result.personGroup)
+                return fail(code:"personGroup.not.found")
+
+            result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }
+
+            result.assignedGroupInstance = new AssignedGroup()
+            result.assignedGroupInstance.properties = params
+
+            if(result.assignedGroupInstance.hasErrors() || !result.assignedGroupInstance.save())
+                return fail(code:"default.create.failure")
+
+            // Record a taskModification for everyone except "system".
+            if(authService.currentUser.id != 1) {
+                def taskModification = new TaskModification(person: authService.currentUser,
+                                                        taskModificationType: TaskModificationType.get(10),
+                                                        task: result.assignedGroupInstance.task)
+
+                if(!taskModification.save())
+                    return fail(field:"taskModifications", code:"task.modifications.failedToSave")
+            }
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    } // end save()
+
+    def personsInGroup(params) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["PersonGroup", params.personGroup?.id] ]
+            return result
+        }
+
+        if(!params.personGroup?.id?.isLong())
+            return fail(code:"default.not.found")
+
+        result.personGroup = PersonGroup.createCriteria().get {
+            idEq(params.personGroup.id.toLong())
+            fetchMode("persons", FM.EAGER)
+        }
+
+        if(!result.personGroup)
+            return fail(code:"default.not.found")
+
+        result.personsInGroup = result.personGroup.persons.sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }
+
+        // Success.
+        return result
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/AssignedPersonService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AssignedPersonService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AssignedPersonService.groovy	(revision 875)
@@ -0,0 +1,191 @@
+class AssignedPersonService {
+
+    boolean transactional = false
+
+    def authService
+
+    def delete(params) {
+        AssignedPerson.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assignedPersonInstance && m.field)
+                    result.assignedPersonInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssignedPerson", params.id] ]
+                return result
+            }
+
+            result.assignedPersonInstance = AssignedPerson.get(params.id)
+
+            if(!result.assignedPersonInstance)
+                return fail(code:"default.not.found")
+
+            def taskModification = new TaskModification(person: authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(11),
+                                                    task: result.assignedPersonInstance.task)
+
+            if(!taskModification.save())
+                return fail(field:"taskModifications", code:"task.modifications.failedToSave")
+
+            try {
+                result.assignedPersonInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } //end withTransaction
+    } // end delete()
+
+    def edit(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["AssignedPerson", params.id] ]
+            return result
+        }
+
+        result.assignedPersonInstance = AssignedPerson.get(params.id)
+
+        if(!result.assignedPersonInstance)
+            return fail(code:"default.not.found")
+
+        result.person = result.assignedPersonInstance.person
+        result.groupsForPerson = result.person.personGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+        // Success.
+        return result
+    }
+
+    def update(params) {
+        AssignedPerson.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assignedPersonInstance && m.field)
+                    result.assignedPersonInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssignedPerson", params.id] ]
+                return result
+            }
+
+            result.person = Person.get(params.person.id)
+
+            // Prevent a null property reference.
+            if(!result.person)
+                return fail(code:"person.not.found")
+
+            result.groupsForPerson = result.person.personGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+            result.assignedPersonInstance = AssignedPerson.get(params.id)
+
+            if(!result.assignedPersonInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.assignedPersonInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            result.assignedPersonInstance.properties = params
+
+            if(result.assignedPersonInstance.hasErrors() || !result.assignedPersonInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person: authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(11),
+                                                    task: result.assignedPersonInstance.task)
+
+            if(!taskModification.save())
+                return fail(field:"taskModifications", code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end update()
+
+    def create(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["AssignedPerson", params.id] ]
+            return result
+        }
+
+        if(!params.task?.id)
+            fail(code:"assignedPerson.task.not.found")
+
+        result.assignedPersonInstance = new AssignedPerson()
+        result.assignedPersonInstance.properties = params
+
+        result.person = Person.list().sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }[0] // Get the first result.
+        result.groupsForPerson = result.person.personGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+        // Success.
+        return result
+    }
+
+    def save(params) {
+        AssignedPerson.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assignedPersonInstance && m.field)
+                    result.assignedPersonInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssignedPerson", params.id] ]
+                return result
+            }
+
+            result.person = Person.get(params.person.id)
+
+            // Prevent a null property reference.
+            if(!result.person)
+                return fail(code:"person.not.found")
+
+            result.groupsForPerson = result.person.personGroups?.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+            result.assignedPersonInstance = new AssignedPerson()
+            result.assignedPersonInstance.properties = params
+
+            if(result.assignedPersonInstance.hasErrors() || !result.assignedPersonInstance.save())
+                return fail(code:"default.create.failure")
+
+            // Record a taskModification for every one except "system".
+            if(authService.currentUser.id != 1) {
+                def taskModification = new TaskModification(person: authService.currentUser,
+                                                        taskModificationType: TaskModificationType.get(11),
+                                                        task: result.assignedPersonInstance.task)
+
+                if(!taskModification.save())
+                    return fail(field:"taskModifications", code:"task.modifications.failedToSave")
+            }
+
+            // success
+            return result
+
+        } //end withTransaction
+    } // end save()
+
+    def groupsForPerson(params) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["Person", params.person?.id] ]
+            return result
+        }
+
+        result.person = Person.get(params.person?.id)
+
+        if(!result.person)
+            return fail(code:"default.not.found")
+
+        result.groupsForPerson = result.person.personGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+        // Success.
+        return result
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/AuthService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/AuthService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/AuthService.groovy	(revision 875)
@@ -0,0 +1,49 @@
+/**
+ * Provides a service class with some methods that integrate the Person domain class and Acegi security.
+ *
+ */
+class AuthService {
+
+    boolean transactional = false
+
+    def authenticateService
+
+    /**
+    * Get the current user in a safe way to avoid a null userDomain.
+    * @returns The current user or the 'system' person (Person #1) if userDomain() is not active.
+    */
+    def getCurrentUser() {
+        if(authenticateService.userDomain()) {
+            return Person.get(authenticateService.userDomain().id)
+        }
+        else {
+            log.warn "userDomain not active, attempting to return Person #1."
+            return Person.get(1)
+        }
+    }
+
+    /**
+    * Convenience wrapper around authenticateService.encodePassword().
+    * @param passClearText The clear text password to encode.
+    * @returns The encoded password.
+    */
+    def encodePassword(passClearText) {
+        authenticateService.encodePassword(passClearText)
+    }
+
+    /**
+    * Generate a random password.
+    * @returns The generated password.
+    */
+    def getRandomPassword() {
+        def passwd = ""
+        def pool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
+        def rand = new Random(System.currentTimeMillis())
+
+        for(i in 0..10)
+            passwd += pool[rand.nextInt(pool.length())]
+
+        return passwd
+    }
+
+}
Index: /branches/features/grailsUpgrade/grails-app/services/ContactService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/ContactService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/ContactService.groovy	(revision 875)
@@ -0,0 +1,99 @@
+/**
+ * Provides a service class with methods to interact with the Contact domain class.
+ * Contact stores contact details for various objects in the database.
+ */
+class ContactService {
+
+    boolean transactional = false
+
+    def delete(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["Contact", params.id] ]
+            return result
+        }
+
+        result.contactInstance = Contact.get(params.id)
+
+        if(!result.contactInstance)
+            return fail(code:"default.not.found")
+
+        result.ownerInstance = getOwner(result.contactInstance)
+
+        try {
+            result.contactInstance.delete(flush:true)
+            return result //Success.
+        }
+        catch(org.springframework.dao.DataIntegrityViolationException e) {
+            return fail(code:"default.delete.failure")
+        }
+
+    }
+
+    def create(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["Contact", params.id] ]
+            return result
+        }
+
+        result.ownerInstance = getOwner(params)
+        if(!result.ownerInstance)
+            return fail(code:"contact.owner.not.found")
+
+        result.contactInstance = new Contact()
+        result.contactInstance.properties = params
+
+        // success
+        return result
+    }
+
+    def save(params) {
+        def result = [:]
+        def fail = { Map m ->
+            if(result.contactInstance && m.field)
+                result.contactInstance.errors.rejectValue(m.field, m.code)
+            result.error = [ code: m.code, args: ["Contact", params.id] ]
+            return result
+        }
+
+        result.ownerInstance = getOwner(params)
+        if(!result.ownerInstance)
+            return fail(code:"contact.owner.not.found")
+
+        result.contactInstance = new Contact(params)
+
+        if(result.contactInstance.hasErrors() || !result.contactInstance.save(flush: true))
+            return fail(code:"default.create.failure")
+
+        // success
+        return result
+    }
+
+    private getOwner(Map params) {
+        def ownerInstance
+
+        if(params.supplier?.id)
+            return ownerInstance = Supplier.get(params.supplier.id)
+        if(params.person?.id)
+            return ownerInstance = Person.get(params.person.id)
+        if(params.site?.id)
+            return ownerInstance = Site.get(params.site.id)
+
+        return false
+    }
+
+    private getOwner(Object object) {
+        def ownerInstance
+
+        if(object.supplier)
+            return ownerInstance = object.supplier
+        if(object.person)
+            return ownerInstance = object.person
+        if(object.site)
+            return ownerInstance = object.site
+
+        return false
+    }
+
+} // end of class
Index: /branches/features/grailsUpgrade/grails-app/services/CreateBulkDataService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/CreateBulkDataService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/CreateBulkDataService.groovy	(revision 875)
@@ -0,0 +1,391 @@
+import grails.util.GrailsUtil
+
+/**
+* Provides a data service to create a large volume of test data for load testing.
+*/
+class  CreateBulkDataService {
+
+    boolean transactional = false
+
+    def authService
+    def taskService
+    def dateUtilService
+    def appConfigService
+    def createDataService
+    def searchableService
+    def assignedGroupService
+    def assignedPersonService
+    def inventoryItemService
+
+    def sessionFactory
+    def grailsApplication
+    def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
+
+    def startTime
+    def lastBatchStarted
+
+/*******************************************
+Start of Group methods.
+Generally use these methods to create data.
+*******************************************/
+
+    /**
+    * Make a run of data creation.
+    */
+    def createAll() {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: m.args ]
+            return result
+        }
+
+        if(GrailsUtil.environment != "development")
+            return fail(code: 'default.not.development.environment.failure')
+
+        createDataService.stopSearchableIndex()
+
+        log.info "Creating BULK data..."
+
+        // Person and Utils
+        log.info "Creating persons..."
+        createBulkTestPersons()
+//         createBulkTestSites()
+//         createBulkTestDepartments()
+//         createBulkTestSuppliers()
+
+        // Assets
+//         createBulkTestTaskProcedure()
+//         createBulkTestMaintenanceActions()
+//         createBulkTestSections()
+//         createBulkTestAssets()
+//         createBulkTestAssetExtenedAttributes()
+//         createBulkTestAssetSubItems()
+//         createBulkTestAssetSubItemExtenedAttributes()
+
+        // Inventory
+        log.info "Creating inventory..."
+//         createBulkTestInventoryStores()  /// @todo: Perhaps a 'createQuickStartData' method?
+        createBulkTestInventoryLocations()
+//         createBulkTestInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method?
+        createBulkTestInventoryItems()
+
+        // Tasks
+        log.info "Creating tasks..."
+        createBulkTestTasks()
+//         createBulkTestEntries()
+//         createBulkTestAssignedGroups()
+//         createBulkTestAssignedPersons()
+//         createBulkTestTaskRecurringSchedules()
+
+        log.info "Creating BULK data...complete."
+
+        createDataService.startSearchableIndex()
+
+        return result
+
+    } // create()
+
+    /**
+    * Make a run of inventory data creation.
+    */
+    def createBulkInventoryTestData() {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: m.args ]
+            return result
+        }
+
+        if(GrailsUtil.environment != "development")
+            return fail(code: 'default.not.development.environment.failure')
+
+        createDataService.stopSearchableIndex()
+
+        log.info "Creating BULK data..."
+
+        // Inventory
+        log.info "Creating inventory..."
+//         createBulkTestInventoryStores()  /// @todo: Perhaps a 'createQuickStartData' method?
+        createBulkTestInventoryLocations()
+//         createBulkTestInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method?
+        createBulkTestInventoryItems()
+
+        log.info "Creating BULK data...complete."
+
+        createDataService.startSearchableIndex()
+
+        return result
+
+    } // createBulkInventoryTestData()
+
+/******************
+Start of Person
+*******************/
+
+    def createBulkTestPersons() {
+        //Person
+        def passClearText = "pass"
+        def passwordEncoded = authService.encodePassword(passClearText)
+        def personInstance
+
+        def start = Person.count() + 1
+        def end = start + 100
+
+        def range = start..end
+
+        def loginName = "BtLoginName"
+        String btLoginName
+        def firstName = "BtFirstName"
+        String btFirstName
+        def lastName = "BtLastName"
+
+        def authority2 = Authority.get(2)
+        def authority3 = Authority.get(3)
+        def personGroup1 = PersonGroup.get(1)
+        def personGroup2 = PersonGroup.get(2)
+        def personGroup3 = PersonGroup.get(3)
+        def personGroup4 = PersonGroup.get(4)
+        def personGroup5 = PersonGroup.get(5)
+
+        range.each() {
+
+            btLoginName = loginName + it
+            btFirstName = firstName + it
+
+            personInstance = new Person(loginName: btLoginName,
+                                        firstName: btFirstName,
+                                        lastName: lastName,
+                                        pass: passClearText,
+                                        password: passwordEncoded)
+            saveAndTest(personInstance)
+            personInstance.addToAuthorities(authority2)
+            personInstance.addToAuthorities(authority3)
+            personInstance.addToPersonGroups(personGroup1)
+            personInstance.addToPersonGroups(personGroup2)
+            personInstance.addToPersonGroups(personGroup3)
+            personInstance.addToPersonGroups(personGroup4)
+            personInstance.addToPersonGroups(personGroup5)
+
+        }
+
+    } // createBulkTestPersons()
+
+/*********************
+START OF TASK
+*********************/
+
+    def createBulkTestTasks() {
+
+        def taskResult
+        def p = [:]
+
+        def start = Task.count() + 1
+        def end = start + 10000
+
+        def range = start..end
+
+
+        def taskGroup1 = TaskGroup.get(1)
+        def taskPriority2 = TaskPriority.get(2)
+        def taskType3 = TaskType.get(3)
+        def leadPerson2 = Person.get(2)
+
+        def description = "Bulk test data "
+        String btDescription
+        def comment1 = "Has been noted as problematic, try recalibrating."
+        def today = dateUtilService.today
+
+        startTime = System.currentTimeMillis()
+        lastBatchStarted = startTime
+
+        range.each() {
+
+            if(it % 100 == 0) {
+                logStatus("Creating task #" + it)
+                cleanUpGorm()
+            }
+
+            btDescription = description + it
+
+            //Task #1
+            p = [taskGroup: taskGroup1,
+                    taskPriority: taskPriority2,
+                    taskType: taskType3,
+                    leadPerson: leadPerson2,
+                    description: btDescription,
+                    comment: comment1,
+                    targetStartDate: today]
+
+            taskResult = taskService.save(p)
+        }
+
+    } // createBulkTestTasks()
+
+    def createBulkTestEntries() {
+
+        def entryResult
+        def p = [:]
+
+        def range = 1..10
+        def task1 = Task.get(1)
+        def entryType1 = EntryType.get(1)
+        def comment1 = "This is a bulk test entry."
+        def durationMinute1 = 20
+
+        range.each() {
+
+            p = [task: task1,
+                    entryType: entryType1,
+                    comment: comment1,
+                    durationMinute: durationMinute1]
+
+            entryResult = taskService.saveEntry(p)
+
+        }
+
+    } // createBulkTestEntries()
+
+
+/**************************
+START OF INVENTORY
+**************************/
+
+    def createBulkTestInventoryLocations() {
+
+        def inventoryLocationResult
+        def p = [:]
+
+        def start = InventoryLocation.count() + 1
+        def end = start + 50
+
+        def range = start..end
+
+
+        def inventoryStore1 = InventoryStore.read(1)
+
+        def name = "Bulk test location "
+        def btName = ''
+
+        startTime = System.currentTimeMillis()
+        lastBatchStarted = startTime
+
+        range.each() {
+
+            if(it % 25 == 0) {
+                logStatus("Creating inventory location #" + it)
+                cleanUpGorm()
+            }
+
+            btName = name + it
+
+            p = [inventoryStore: inventoryStore1,
+                    name: btName]
+
+            inventoryLocationResult = new InventoryLocation(p).save()
+        } // each()
+
+    } // createBulkTestInventoryLocations()
+
+    def createBulkTestInventoryItems() {
+
+        def inventoryItemInstance
+        def p = [:]
+
+        def pictureResource = grailsApplication.mainContext.getResource('images/logo.png')
+
+        def start = InventoryItem.count() + 1
+        def end = start + 250
+
+        def range = start..end
+
+        def inventoryLocation
+        def inventoryLocationIndex = 0
+        def inventoryLocationList = InventoryLocation.findAll()
+        def unitOfMeasure2 = UnitOfMeasure.read(2)
+        def inventoryType1 = InventoryType.read(1)
+        def inventoryGroup1 = InventoryGroup.read(1)
+
+        def name = "Bulk test inventory item "
+        def btName = ''
+
+        startTime = System.currentTimeMillis()
+        lastBatchStarted = startTime
+
+        range.each() {
+
+            if(it % 50 == 0) {
+                logStatus("Creating inventory item #" + it)
+                cleanUpGorm()
+            }
+
+            // Spread the inventoryItems across all available locations.
+            if(inventoryLocationIndex < inventoryLocationList.size()) {
+                inventoryLocation = inventoryLocationList[inventoryLocationIndex]
+            }
+            else {
+                inventoryLocationIndex = 0
+                inventoryLocation = inventoryLocationList[inventoryLocationIndex]
+            }
+            inventoryLocationIndex++
+
+            // Change the name for each inventoryItem.
+            btName = name + it
+
+            p = [inventoryGroup: inventoryGroup1,
+                    inventoryType: inventoryType1,
+                    unitOfMeasure: unitOfMeasure2,
+                    inventoryLocation: inventoryLocation,
+                    name: btName,
+                    description: "Bulk test data",
+                    unitsInStock: 2,
+                    reorderPoint: 0]
+
+            inventoryItemInstance = new InventoryItem(p)
+            saveAndTest(inventoryItemInstance)
+
+            def pictureResult = inventoryItemService.savePicture(inventoryItemInstance, pictureResource)
+
+            if(pictureResult.error)
+                log.error pictureResult.error
+        } // each()
+
+    } // createBulkTestInventoryItems()
+
+    /**
+    * This cleans up the hibernate session and a grails map.
+    * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
+    * The hibernate session flush is normal for hibernate.
+    * The map is apparently used by grails for domain object validation errors.
+    * A starting point for clean up is every 100 objects.
+    */
+    def cleanUpGorm() {
+        def session = sessionFactory.currentSession
+        session.flush()
+        session.clear()
+        propertyInstanceMap.get().clear()
+    }
+
+    def logStatus(String message) {
+        def batchEnded = System.currentTimeMillis()
+        def seconds = (batchEnded-lastBatchStarted)/1000
+        def total = (batchEnded-startTime)/1000
+        log.info "${message}, last: ${seconds}s, total: ${total}s"
+        lastBatchStarted = batchEnded
+    }
+
+
+/****************************************
+Call this function instead of .save()
+*****************************************/
+    private boolean saveAndTest(object) {
+        if(!object.save()) {
+//             BulkTestDataSuccessful = false
+            log.error "'${object}' failed to save!"
+            log.error object.errors
+            return false
+        }
+        return true
+    }
+
+} // end class.
Index: /branches/features/grailsUpgrade/grails-app/services/CreateDataService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/CreateDataService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/CreateDataService.groovy	(revision 875)
@@ -0,0 +1,1784 @@
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+
+/**
+* Provides a data service to create base and demo data.
+* Beware that most, if not all, BASE data is referenced by "Id" throughout the program.
+* This allows changing the text of the 'name' property to something of the same meaning.
+* But be sure to maintain the correct Id during creation, indicated by #1, #2 etc.
+* Task.list()[0] is used to allow integration testing with DEMO data, where Id's may change due to create-delete.
+*/
+class  CreateDataService {
+
+    boolean transactional = false
+
+    def authService
+    def taskService
+    def dateUtilService
+    def appConfigService
+    def searchableService
+    def inventoryItemService
+    def assignedGroupService
+    def assignedPersonService
+
+    def grailsApplication
+
+/*******************************************
+Start of Group methods.
+Generally use these methods to create data.
+*******************************************/
+
+    /**
+    * Always call this at startup to ensure that we have admin access
+    * and that the system pseudo person is available.
+    */
+    def ensureSystemAndAdminAccess() {
+        if(!Authority.findByAuthority("ROLE_AppAdmin") ) {
+            log.warn "ROLE_AppAdmin not found, calling createAdminAuthority()."
+            createAdminAuthority()
+        }
+        if(!Person.findByLoginName("system") ) {
+            log.warn "LoginName 'system' not found, calling createSystemPerson()."
+            createSystemPerson()
+        }
+        if(!Person.findByLoginName("admin") ) {
+            log.warn "LoginName 'admin' not found, calling createAdminPerson()."
+            createAdminPerson()
+        }
+    }
+
+    /**
+    * Create the base data required for the application to function.
+    */
+    def createBaseData() {
+
+        if(appConfigService.exists("baseDataCreated")) {
+            log.info "Base data previously created."
+            return false
+        }
+
+        log.info "Creating base data."
+
+        // Person and Utils
+        createBaseAuthorities()
+        createBasePersonGroupTypes()
+        createBasePersonGroups()
+        createBaseDefinitions()
+        createBaseUnitsOfMeasure()
+        createBasePeriods()
+        createBaseSupplierTypes()
+        createBaseAddressTypes()
+        createBaseContactTypes()
+        createBaseMaintenancePolicies()
+        createBaseInventoryItemPurchaseTypes()
+        createBaseConditionSeverity()
+
+        // Assets
+        createBaseExtenededAttributeTypes()
+
+        // Inventory
+        createBaseInventoryTypes()
+        createBaseInventoryMovementTypes()
+
+        // Tasks
+        createBaseTaskGroups()
+        createBaseTaskStatus()
+        createBaseTaskPriorities()
+        createBaseTaskBudgetStatus()
+        createBaseTaskTypes()
+        createBaseTaskModificationTypes()
+        createBaseEntryTypes()
+
+        // Record that data has been created.
+        appConfigService.set("baseDataCreated")
+    }
+
+    /**
+    * Create demo data for some example sites.
+    */
+    def createDemoData() {
+
+        if(!appConfigService.exists("baseDataCreated")) {
+            log.error "Demo data cannot be created until base data has been created."
+            return false
+        }
+
+        if(appConfigService.exists("demoDataCreated")) {
+            log.error "Demo data has already been created, will NOT recreate."
+            return false
+        }
+
+        if(appConfigService.exists("demoDataCreationDisabled")) {
+            log.error "Demo data creation has been disabled, will NOT create."
+            return false
+        }
+
+        log.info "Creating demo data..."
+
+        // Person and Utils
+        createDemoSites()
+        createDemoDepartments()
+        createDemoSuppliers()
+        createDemoProductionReference()
+        createDemoPurchasingGroups()  /// @todo: Perhaps a 'createQuickStartData' method?
+        createDemoCostCodes()
+        createDemoPersons()
+
+        // Assets
+        createDemoSections()
+        createDemoAssetTree()
+        createDemoAssetExtendedAttributes()
+        createDemoAssetSubItemExtendedAttributes()
+
+        // Inventory
+        createDemoInventoryStores()  /// @todo: Perhaps a 'createQuickStartData' method?
+        createDemoInventoryLocations()
+        createDemoInventoryGroups() /// @todo: Perhaps a 'createQuickStartData' method?
+        createDemoInventoryItems()
+
+        // Tasks
+        createDemoTasks()
+        createDemoEntries()
+        createDemoAssignedGroups()
+        createDemoAssignedPersons()
+//         createDemoTaskProcedure()
+//         createDemoMaintenanceActions()
+        createDemoTaskRecurringSchedules()
+
+        // Record that data has been created.
+        appConfigService.set("demoDataCreated")
+    }
+
+/******************
+Start of Person
+*******************/
+
+    def createAdminAuthority() {
+        def authInstance
+
+        // Authority #1
+        authInstance = new Authority(description:"Application Admin, not required for daily use! \
+                                                                                Grants full admin access to the application.",
+                                        authority:"ROLE_AppAdmin")
+        saveAndTest(authInstance)
+    }
+
+    def createBaseAuthorities() {
+
+        def authInstance
+
+        // Authority #2
+        authInstance = new Authority(description:"Business Manager, grants full management access.",
+                                                            authority:"ROLE_Manager")
+        saveAndTest(authInstance)
+
+        // Authority #3
+        authInstance = new Authority(description:"Application User, all application users need this base role \
+                                                                                    to allow login.",
+                                                            authority:"ROLE_AppUser")
+        saveAndTest(authInstance)
+
+        // Authority #4
+        authInstance = new Authority(description:"Task Manager",
+                                                            authority:"ROLE_TaskManager")
+        saveAndTest(authInstance)
+
+        // Authority #5
+        authInstance = new Authority(description:"Task User",
+                                                            authority:"ROLE_TaskUser")
+        saveAndTest(authInstance)
+
+        // Authority #6
+        authInstance = new Authority(description:"Inventory Manager",
+                                                            authority:"ROLE_InventoryManager")
+        saveAndTest(authInstance)
+
+        // Authority #7
+        authInstance = new Authority(description:"Inventory User",
+                                                            authority:"ROLE_InventoryUser")
+        saveAndTest(authInstance)
+
+        // Authority #8
+        authInstance = new Authority(description:"Asset Manager",
+                                                            authority:"ROLE_AssetManager")
+        saveAndTest(authInstance)
+
+        // Authority #9
+        authInstance = new Authority(description:"Asset User",
+                                                            authority:"ROLE_AssetUser")
+        saveAndTest(authInstance)
+
+        // Authority #10
+        authInstance = new Authority(description:"Production Manager",
+                                                            authority:"ROLE_ProductionManager")
+        saveAndTest(authInstance)
+
+        // Authority #11
+        authInstance = new Authority(description:"Production User",
+                                                            authority:"ROLE_ProductionUser")
+        saveAndTest(authInstance)
+    }
+
+    void createBasePersonGroupTypes() {
+
+        //PersonGroupType.
+        def personGroupTypeInstance
+        personGroupTypeInstance = new PersonGroupType(name:"Team")
+        saveAndTest(personGroupTypeInstance)
+        personGroupTypeInstance = new PersonGroupType(name:"Contractor")
+        saveAndTest(personGroupTypeInstance)
+        personGroupTypeInstance = new PersonGroupType(name:"Project Team")
+        saveAndTest(personGroupTypeInstance)
+    }
+
+    void createBasePersonGroups() {
+
+        //PersonGroup
+        def personGroupInstance
+        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(1),
+                                                                                name:"Electrical - General")
+        saveAndTest(personGroupInstance)
+        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(1),
+                                                                                name:"Mechanical - General")
+        saveAndTest(personGroupInstance)
+        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(1),
+                                                                                name:"Production")
+        saveAndTest(personGroupInstance)
+        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(2),
+                                                                                name:"AirCon Contractor")
+        saveAndTest(personGroupInstance)
+        personGroupInstance = new PersonGroup(personGroupType:PersonGroupType.get(3),
+                                                                                name:"gnuMims")
+        saveAndTest(personGroupInstance)
+    }
+
+    def createSystemPerson() {
+        //Person
+        def passClearText = "pass"
+        def passwordEncoded = authService.encodePassword(passClearText)
+        def personInstance
+
+        //Person #1
+        personInstance = new Person(loginName:"system",
+                                    firstName:"gnuMims",
+                                    lastName:"System",
+                                    description:'''This is a pseudo person that the application uses to insert data. DO NOT
+                                                        assign login authorities or change the details of this person.''',
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+    }
+
+    def createAdminPerson() {
+        //Person
+        def passClearText = "pass"
+        def passwordEncoded = authService.encodePassword(passClearText)
+        def personInstance
+
+        //Person #2
+        personInstance = new Person(loginName:"admin",
+                                    firstName:"Admin",
+                                    lastName:"Powers",
+                                    description:'''Every time the application starts it ensures that the 'admin' login name is available.
+                                                        DO update the password and other details but keep the login name as 'admin'. ''',
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(1))
+    }
+
+    def createBasePersons() {
+    }
+
+    def createDemoPersons() {
+        //Person
+        def passClearText = "pass"
+        def passwordEncoded = authService.encodePassword(passClearText)
+        def personInstance
+
+        //Person #1 is system.
+        //Person #2 is admin.
+
+        //Person #3
+        personInstance = new Person(loginName:"manager",
+                                    firstName:"Demo",
+                                    lastName:"Manager",
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(2)) // ROLE_Manager.
+        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
+        personInstance.addToPersonGroups(PersonGroup.get(1))
+        personInstance.addToPurchasingGroups(PurchasingGroup.get(1))
+        personInstance.addToPurchasingGroups(PurchasingGroup.get(2))
+
+        //Person #4
+        personInstance = new Person(loginName:"user",
+                                    firstName:"Demo",
+                                    lastName:"User",
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
+        personInstance.addToAuthorities(Authority.get(5)) // ROLE_TaskManager.
+        personInstance.addToAuthorities(Authority.get(7)) // ROLE_InventoryUser.
+        personInstance.addToAuthorities(Authority.get(9)) // ROLE_AssetUser.
+        personInstance.addToPersonGroups(PersonGroup.get(1))
+
+        //Person #5
+        personInstance = new Person(loginName:"craig",
+                                    firstName:"Craig",
+                                    lastName:"SuperSparky",
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(3))
+        personInstance.addToAuthorities(Authority.get(5))
+        personInstance.addToAuthorities(Authority.get(7))
+        personInstance.addToAuthorities(Authority.get(9))
+        personInstance.addToPersonGroups(PersonGroup.get(1))
+
+        //Person #6
+        personInstance = new Person(loginName:"john",
+                                    firstName:"John",
+                                    lastName:"SuperFitter",
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(3))
+        personInstance.addToAuthorities(Authority.get(5))
+        personInstance.addToAuthorities(Authority.get(7))
+        personInstance.addToAuthorities(Authority.get(9))
+        personInstance.addToPersonGroups(PersonGroup.get(2))
+
+        //Person #7
+        personInstance = new Person(loginName:"production manager",
+                                    firstName:"Production",
+                                    lastName:"Manager",
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
+        personInstance.addToAuthorities(Authority.get(10)) // ROLE_ProductionManager.
+        personInstance.addToPersonGroups(PersonGroup.get(3))
+
+        //Person #8
+        personInstance = new Person(loginName:"production",
+                                    firstName:"Production",
+                                    lastName:"User",
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
+        personInstance.addToAuthorities(Authority.get(11)) // ROLE_ProductionUser.
+        personInstance.addToPersonGroups(PersonGroup.get(3))
+
+        //Person #9
+        personInstance = new Person(loginName:"testmanager",
+                                    firstName:"Test",
+                                    lastName:"Manager",
+                                    pass:passClearText,
+                                    password:passwordEncoded)
+        saveAndTest(personInstance)
+        personInstance.addToAuthorities(Authority.get(3)) // ROLE_AppUser.
+        personInstance.addToAuthorities(Authority.get(4)) // ROLE_TaskManager.
+        personInstance.addToAuthorities(Authority.get(6)) // ROLE_InventoryManager.
+        personInstance.addToAuthorities(Authority.get(8)) // ROLE_AssetManager.
+        personInstance.addToPersonGroups(PersonGroup.get(3))
+    }
+
+/***********************
+START OF UTILITIES
+***********************/
+
+    //These can redefined by the site at deployment time.
+    /// @todo: build an admin view so that only the value (definition) can be changed.
+    def createBaseDefinitions() {
+        appConfigService.set("Department Definition", "A department as recongised by accounting.")
+        appConfigService.set("Site Definition", "The plant, work or production site.")
+        appConfigService.set("Section Definition", "A logical grouping of assets, which may be an area, system or process \
+                                            as determined by design.")
+        appConfigService.set("Asset Definition",
+                                            "The complete asset as it is known on the site. \
+                                            Often purchased as a whole with the primary purpose of returning value by performing a function. \
+                                            An asset is made up of 1 or more sub assets and performs a complete function as specified by the designer.")
+        appConfigService.set("Asset Sub Item 1 Name",
+                                            "Sub Asset")
+        appConfigService.set("Asset Sub Item 1 Definition",
+                                            "A machine that performs part of a complete asset's function and often has a model number.")
+        appConfigService.set("Asset Sub Item 2 Name",
+                                            "Functional Assembly")
+        appConfigService.set("Asset Sub Item 2 Definition",
+                                            "Functional Assemblies are taken from the designer's functional list for the sub asset and are made up of sub \
+                                            assemblies that together perform that function.")
+        appConfigService.set("Asset Sub Item 3 Name",
+                                            "Sub Assembly Group")
+        appConfigService.set("Asset Sub Item 3 Definition",
+                                            "Group or type of part.")
+        appConfigService.set("Asset Sub Item 4 Name",
+                                            "Component Item")
+        appConfigService.set("Asset Sub Item 4 Definition",
+                                            "The smallest part that would be analysed for failure.")
+    }
+
+    def createDemoSites() {
+        //Site
+        def siteInstance
+
+        siteInstance = new Site(name: "CSM",
+                                                    description: "Creek Side Mill")
+        saveAndTest(siteInstance)
+
+        siteInstance = new Site(name: "Jasper Street Depot",
+                                                    description: "Storage depot on Jasper Street.")
+        saveAndTest(siteInstance)
+
+        siteInstance = new Site(name: "River Press",
+                                                    description: "Printing press site")
+        saveAndTest(siteInstance)
+    }
+
+    def createDemoDepartments() {
+
+        //Department
+        def departmentInstance
+
+        //Department #1
+        departmentInstance = new Department(name: "Print Centre",
+                                                                                description: "Printing Department",
+                                                                                site: Site.get(1))
+        saveAndTest(departmentInstance)
+
+        //Department #2
+        departmentInstance = new Department(name: "Pulp Mill",
+                                                                                description: "Business Department",
+                                                                                site: Site.get(2))
+        saveAndTest(departmentInstance)
+    }
+
+    def createBaseUnitsOfMeasure() {
+
+        //UnitOfMeasure
+        def unitOfMeasureInstance
+
+        //UnitOfMeasure #1
+        unitOfMeasureInstance = new UnitOfMeasure(name: "each")
+        saveAndTest(unitOfMeasureInstance)
+
+        //UnitOfMeasure #2
+        unitOfMeasureInstance = new UnitOfMeasure(name: "meter(s)")
+        saveAndTest(unitOfMeasureInstance)
+
+        //UnitOfMeasure #3
+        unitOfMeasureInstance = new UnitOfMeasure(name: "box(es)")
+        saveAndTest(unitOfMeasureInstance)
+
+        //UnitOfMeasure #4
+        unitOfMeasureInstance = new UnitOfMeasure(name: "litre(s)")
+        saveAndTest(unitOfMeasureInstance)
+
+        //UnitOfMeasure #5
+        unitOfMeasureInstance = new UnitOfMeasure(name: "kilogram(s)")
+        saveAndTest(unitOfMeasureInstance)
+
+        //UnitOfMeasure #6
+        unitOfMeasureInstance = new UnitOfMeasure(name: "gram(s)")
+        saveAndTest(unitOfMeasureInstance)
+    }
+
+    def createBasePeriods() {
+
+        //Period
+        def periodInstance
+
+        //Period #1
+        periodInstance = new Period(period: "Day(s)")
+        saveAndTest(periodInstance)
+
+        //Period #2
+        periodInstance = new Period(period: "Week(s)")
+        saveAndTest(periodInstance)
+
+        //Period #3
+        periodInstance = new Period(period: "Month(s)")
+        saveAndTest(periodInstance)
+
+        //Period #4
+        periodInstance = new Period(period: "Year(s)")
+        saveAndTest(periodInstance)
+    }
+
+    def createBaseSupplierTypes() {
+
+        // SupplierType
+        def supplierTypeInstance
+
+        // SupplierType #1
+        supplierTypeInstance = new SupplierType(name: "Unknown",
+                                                                    description: "Unknown supplier type")
+        saveAndTest(supplierTypeInstance)
+
+        // SupplierType #2
+        supplierTypeInstance = new SupplierType(name: "OEM",
+                                                                    description: "Original equipment supplier")
+        saveAndTest(supplierTypeInstance)
+
+        // SupplierType #3
+        supplierTypeInstance = new SupplierType(name: "Local",
+                                                                    description: "Local supplier")
+        saveAndTest(supplierTypeInstance)
+    }
+
+    def createBaseAddressTypes() {
+
+        // AddressType
+        def addressTypeInstance
+
+        // AddressType #1
+        addressTypeInstance = new AddressType(name: "Postal",
+                                                                                description: "A postal address.")
+        saveAndTest(addressTypeInstance)
+
+        // AddressType #2
+        addressTypeInstance = new AddressType(name: "Physical",
+                                                                                description: "A physical address.")
+        saveAndTest(addressTypeInstance)
+
+        // AddressType #3
+        addressTypeInstance = new AddressType(name: "Postal & Physical",
+                                                                                description: "An address that is both the postal and physical address.")
+        saveAndTest(addressTypeInstance)
+
+        // AddressType #4
+        addressTypeInstance = new AddressType(name: "Invoice",
+                                                                                description: "An address to send invoices to.")
+        saveAndTest(addressTypeInstance)
+
+        // AddressType #5
+        addressTypeInstance = new AddressType(name: "Delivery",
+                                                                                description: "An address to send deliveries to.")
+        saveAndTest(addressTypeInstance)
+    }
+
+    def createBaseContactTypes() {
+
+        // ContactType
+        def contactTypeInstance
+
+        // ContactType #1
+        contactTypeInstance = new ContactType(name: "Email",
+                                                                                description: "Email address.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #2
+        contactTypeInstance = new ContactType(name: "Alternate Email",
+                                                                                description: "Alternate email address.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #3
+        contactTypeInstance = new ContactType(name: "Mobile",
+                                                                                description: "Modile phone number.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #4
+        contactTypeInstance = new ContactType(name: "Work Phone",
+                                                                                description: "Work phone number.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #5
+        contactTypeInstance = new ContactType(name: "Home Phone",
+                                                                                description: "Home phone number.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #6
+        contactTypeInstance = new ContactType(name: "Work Fax",
+                                                                                description: "Work fax number.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #7
+        contactTypeInstance = new ContactType(name: "Home Fax",
+                                                                                description: "Home fax number.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #8
+        contactTypeInstance = new ContactType(name: "Web Site",
+                                                                                description: "Web site address.")
+        saveAndTest(contactTypeInstance)
+
+        // ContactType #9
+        contactTypeInstance = new ContactType(name: "Person",
+                                                                                description: "Contact person.")
+        saveAndTest(contactTypeInstance)
+    }
+
+    def createBaseInventoryItemPurchaseTypes() {
+
+        // InventoryItemPurchaseType
+        def inventoryItemPurchaseTypeInstance
+
+        // InventoryItemPurchaseType #1
+        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Order Placed",
+                                                                                description: "Order has been placed.")
+        saveAndTest(inventoryItemPurchaseTypeInstance)
+
+        // InventoryItemPurchaseType #2
+        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Received B/order To Come",
+                                                                                description: "Order has been partially received.")
+        saveAndTest(inventoryItemPurchaseTypeInstance)
+
+        // InventoryItemPurchaseType #3
+        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Received Complete",
+                                                                                description: "Order has been partially received.")
+        saveAndTest(inventoryItemPurchaseTypeInstance)
+
+        // InventoryItemPurchaseType #4
+        inventoryItemPurchaseTypeInstance = new InventoryItemPurchaseType(name: "Invoice Approved",
+                                                                                description: "Invoice approved for payment.")
+        saveAndTest(inventoryItemPurchaseTypeInstance)
+    }
+
+    def createBaseConditionSeverity() {
+
+        // ConditionSeverity
+        def conditionSeverity
+
+        // ConditionSeverity #1
+        conditionSeverity = new ConditionSeverity(code: 'A',
+                                                                            recommendation: 'Normal Monitoring').save(failOnError:true)
+
+        // ConditionSeverity #2
+        conditionSeverity = new ConditionSeverity(code: 'B',
+                                                                            recommendation: 'Restored To Normal').save(failOnError:true)
+
+        // ConditionSeverity #3
+        conditionSeverity = new ConditionSeverity(code: 'C',
+                                                                            recommendation: 'Increase Monitoring').save(failOnError:true)
+
+        // ConditionSeverity #4
+        conditionSeverity = new ConditionSeverity(code: 'D',
+                                                                            recommendation: 'Schedule Followup').save(failOnError:true)
+
+        // ConditionSeverity #5
+        conditionSeverity = new ConditionSeverity(code: 'E',
+                                                                            recommendation: 'Schedule 2-4 weeks').save(failOnError:true)
+    }
+
+    def createDemoSuppliers() {
+
+        // Supplier
+        def supplierInstance
+
+        // Supplier #1
+        supplierInstance = new Supplier(name: "OEM Distributors",
+                                                                        supplierType: SupplierType.get(2))
+        saveAndTest(supplierInstance)
+
+        // Supplier #2
+        supplierInstance = new Supplier(name: "Mex Holdings",
+                                                                        supplierType: SupplierType.get(3))
+        saveAndTest(supplierInstance)
+    }
+
+    def createDemoProductionReference() {
+
+        // ProductionReference
+        def productionReferenceInstance
+
+        // ProductionReference #1
+        productionReferenceInstance = new ProductionReference(name: "Monday Production")
+        saveAndTest(productionReferenceInstance)
+
+        // ProductionReference #2
+        productionReferenceInstance = new ProductionReference(name: "Tuesday Production")
+        saveAndTest(productionReferenceInstance)
+    }
+
+    void createDemoPurchasingGroups() {
+
+        // PurchasingGroup
+        def purchasingGroupInstance
+
+        purchasingGroupInstance = new PurchasingGroup(name:"R&M")
+        saveAndTest(purchasingGroupInstance)
+
+        purchasingGroupInstance = new PurchasingGroup(name:"Raw Materials")
+        saveAndTest(purchasingGroupInstance)
+
+        purchasingGroupInstance = new PurchasingGroup(name:"Safety")
+        saveAndTest(purchasingGroupInstance)
+    }
+
+    def createDemoCostCodes() {
+
+        // CostCode
+        def costCodeInstance
+
+        // CostCode #1
+        costCodeInstance = new CostCode(name: "Reelstand.172",
+                                                                    purchasingGroup: PurchasingGroup.get(1))
+        saveAndTest(costCodeInstance)
+
+        // CostCode #2
+        costCodeInstance = new CostCode(name: "Reelstand.CAPEX",
+                                                                    purchasingGroup: PurchasingGroup.get(1))
+        saveAndTest(costCodeInstance)
+
+        // CostCode #2
+        costCodeInstance = new CostCode(name: "PrintUnit.123",
+                                                                    purchasingGroup: PurchasingGroup.get(3))
+        saveAndTest(costCodeInstance)
+    }
+
+/*********************
+START OF TASK
+*********************/
+
+    def createBaseTaskGroups() {
+        //TaskGroup
+        def taskGroupInstance
+
+        //TaskGroup #1
+        taskGroupInstance = new TaskGroup(name:"Engineering Activites",
+                                                                            description:"Engineering daily activities")
+        saveAndTest(taskGroupInstance)
+
+        //TaskGroup #2
+        taskGroupInstance = new TaskGroup(name:"Production Activites",
+                                                                            description:"Production daily activities")
+        saveAndTest(taskGroupInstance)
+
+        //TaskGroup #3
+        taskGroupInstance = new TaskGroup(name:"New Projects",
+                                                                            description:"New site projects")
+        saveAndTest(taskGroupInstance)
+
+        //TaskGroup #4
+        taskGroupInstance = new TaskGroup(name:"Electrical Dayshift",
+                                                                            description:"Group for dayshift electrical tasks")
+        saveAndTest(taskGroupInstance)
+
+        //TaskGroup #5
+        taskGroupInstance = new TaskGroup(name:"Electrical Nightshift",
+                                                                            description:"Group for dayshift mechanical tasks")
+        saveAndTest(taskGroupInstance)
+
+        //TaskGroup #6
+        taskGroupInstance = new TaskGroup(name:"Mechanical Dayshift",
+                                                                            description:"Group for nightshift electrical tasks")
+        saveAndTest(taskGroupInstance)
+
+        //TaskGroup #7
+        taskGroupInstance = new TaskGroup(name:"Mechanical Nightshift",
+                                                                            description:"Group for nightshift mechanical tasks")
+        saveAndTest(taskGroupInstance)
+    }
+
+    def createBaseTaskStatus() {
+
+        //TaskStatus
+        def taskStatusInstance
+
+        taskStatusInstance = new TaskStatus(name:"Not Started") // #1
+        saveAndTest(taskStatusInstance)
+
+        taskStatusInstance = new TaskStatus(name:"In Progress") // #2
+        saveAndTest(taskStatusInstance)
+
+        taskStatusInstance = new TaskStatus(name:"Complete") // #3
+        saveAndTest(taskStatusInstance)
+    }
+
+    def createBaseTaskPriorities() {
+
+        //TaskPriority
+        def taskPriorityInstance
+
+        taskPriorityInstance = new TaskPriority(name:"0 - Immediate") // #1
+        saveAndTest(taskPriorityInstance)
+
+        taskPriorityInstance = new TaskPriority(name:"1 - Very High") // #2
+        saveAndTest(taskPriorityInstance)
+
+        taskPriorityInstance = new TaskPriority(name:"2 - High") // #3
+        saveAndTest(taskPriorityInstance)
+
+        taskPriorityInstance = new TaskPriority(name:"3 - Normal") // #4
+        saveAndTest(taskPriorityInstance)
+
+        taskPriorityInstance = new TaskPriority(name:"4 - Low") // #5
+        saveAndTest(taskPriorityInstance)
+
+        taskPriorityInstance = new TaskPriority(name:"5 - Minor") //  #6
+        saveAndTest(taskPriorityInstance)
+    }
+
+    def createBaseTaskBudgetStatus() {
+
+        //TaskBudgetStatus
+        def taskBudgetStatusInstance
+
+        taskBudgetStatusInstance = new TaskBudgetStatus(name:"Unplanned") // #1
+        saveAndTest(taskBudgetStatusInstance)
+
+        taskBudgetStatusInstance = new TaskBudgetStatus(name:"Planned") // #2
+        saveAndTest(taskBudgetStatusInstance)
+    }
+
+    def createBaseTaskTypes() {
+
+        //TaskType
+        def taskTypeInstance
+
+        taskTypeInstance = new TaskType(name:"Immediate Callout") // #1
+        saveAndTest(taskTypeInstance)
+
+        taskTypeInstance = new TaskType(name:"Unscheduled Breakin") // #2
+        saveAndTest(taskTypeInstance)
+
+        taskTypeInstance = new TaskType(name:"Scheduled") // #3
+        saveAndTest(taskTypeInstance)
+
+        taskTypeInstance = new TaskType(name:"Preventative Maintenance") // #4
+        saveAndTest(taskTypeInstance)
+
+        taskTypeInstance = new TaskType(name:"Project") // #5
+        saveAndTest(taskTypeInstance)
+
+        taskTypeInstance = new TaskType(name:"Parent PM") // #6
+        saveAndTest(taskTypeInstance)
+    }
+
+    def createBaseTaskModificationTypes() {
+
+        //ModificationType
+        def taskModificationTypeInstance
+        taskModificationTypeInstance = new TaskModificationType(name:"Created").save()  // #1
+        taskModificationTypeInstance = new TaskModificationType(name:"Started").save()  // #2
+        taskModificationTypeInstance = new TaskModificationType(name:"Modified").save()  // #3
+        taskModificationTypeInstance = new TaskModificationType(name:"Completed").save()  // #4
+        taskModificationTypeInstance = new TaskModificationType(name:"Reopened").save()  // #5
+        taskModificationTypeInstance = new TaskModificationType(name:"Trashed").save()  // #6
+        taskModificationTypeInstance = new TaskModificationType(name:"Restored").save()  // #7
+        taskModificationTypeInstance = new TaskModificationType(name:"Approved").save()  // #8
+        taskModificationTypeInstance = new TaskModificationType(name:"Renege approval").save()  // #9
+        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Assigned Groups)").save()  // #10
+        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Assigned Persons)").save()  // #11
+        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Flagged for attention)").save()  // #12
+        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Attention flag cleared)").save()  // #13
+    }
+
+    def createDemoTasks() {
+
+        def taskResult
+        def p = [:]
+
+        //Task #1
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(1),
+                taskType:TaskType.get(1),
+                leadPerson:Person.get(2),
+                primaryAsset:Asset.get(4),
+                description:"Level sensor not working",
+                comment:"Has been noted as problematic, try recalibrating.",
+                targetStartDate: dateUtilService.today,
+                targetCompletionDate: dateUtilService.today]
+
+        taskResult = taskService.save(p)
+        taskService.approve(taskResult.taskInstance)
+
+        //Task #2
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(2),
+                taskType:TaskType.get(3),
+                leadPerson:Person.get(5),
+                primaryAsset:Asset.get(4),
+                description:"Some follow-up work",
+                comment:"Some help required",
+                targetStartDate: dateUtilService.tomorrow,
+                targetCompletionDate: dateUtilService.tomorrow,
+                parentTask: Task.list()[0]]
+
+        taskResult = taskService.save(p)
+        taskService.approve(taskResult.taskInstance)
+
+        //Task #3
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(2),
+                taskType:TaskType.get(3),
+                leadPerson:Person.get(5),
+                primaryAsset:Asset.get(4),
+                description:"A Sub Task can be created from the 'Sub Task' tab.",
+                comment:"Some help required",
+                targetStartDate: dateUtilService.yesterday,
+                targetCompletionDate: dateUtilService.yesterday,
+                parentTask: Task.list()[0]]
+
+        taskResult = taskService.save(p)
+        taskService.approve(taskResult.taskInstance)
+
+        //Task #4
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(2),
+                taskType:TaskType.get(2),
+                leadPerson:Person.get(4),
+                primaryAsset:Asset.get(4),
+                description:"Please replace sensor at next available opportunity.",
+                comment:"Nothing else has worked. So we now require the part to be replaced.",
+                targetStartDate: dateUtilService.today,
+                targetCompletionDate: dateUtilService.oneWeekFromNow,
+                parentTask: Task.list()[0]]
+
+        taskResult = taskService.save(p)
+        taskService.approve(taskResult.taskInstance)
+
+        //Task #5
+        p = [taskGroup:TaskGroup.findByName("Production Activites"),
+                taskPriority:TaskPriority.get(2),
+                taskType:TaskType.get(3),
+                leadPerson:Person.get(6),
+                primaryAsset:Asset.get(1),
+                description:"Production Task",
+                comment:"Production task for specific production run or shift",
+                targetStartDate: dateUtilService.today - 6,
+                targetCompletionDate: dateUtilService.today - 6]
+
+        taskResult = taskService.save(p)
+        taskService.approve(taskResult.taskInstance)
+
+        //Task #6
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(4),
+                taskType:TaskType.get(6),
+                leadPerson:Person.get(4),
+                primaryAsset:Asset.get(2),
+                description:"This is a recurring preventative maintenance task.",
+                comment:"If there is a parent task specified then this is a generated sub task, if there is a recurring schedule specified then this is a parent task.",
+                targetStartDate: dateUtilService.today,
+                targetCompletionDate: dateUtilService.today + 30]
+
+        taskResult = taskService.save(p)
+        taskService.approve(taskResult.taskInstance)
+
+        //Task #7
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(4),
+                taskType:TaskType.get(6),
+                leadPerson:Person.get(4),
+                primaryAsset:Asset.get(2),
+                description:"100hr Service.",
+                comment:"Based on OEM service.",
+                targetStartDate: dateUtilService.today,
+                targetCompletionDate: dateUtilService.today + 1]
+
+        taskResult = taskService.save(p)
+        taskService.approve(taskResult.taskInstance)
+    }
+
+    def createBaseEntryTypes() {
+
+        //EntryType
+        def entryTypeInstance
+
+        entryTypeInstance = new EntryType(name:"Fault") // #1
+        saveAndTest(entryTypeInstance)
+
+        entryTypeInstance = new EntryType(name:"Cause") // #2
+        saveAndTest(entryTypeInstance)
+
+        entryTypeInstance = new EntryType(name:"Work Done") // #3
+        saveAndTest(entryTypeInstance)
+
+        entryTypeInstance = new EntryType(name:"Production Note") // #4
+        saveAndTest(entryTypeInstance)
+
+        entryTypeInstance = new EntryType(name:"Work Request") // #5
+        saveAndTest(entryTypeInstance)
+
+        entryTypeInstance = new EntryType(name:"PM Entry") // #6
+        saveAndTest(entryTypeInstance)
+    }
+
+    def createDemoEntries() {
+
+        def entryResult
+        def p = [:]
+
+        //Entry #1
+        p = [task: Task.list()[0],
+                entryType: EntryType.get(1),
+                comment: "This level sensor is causing us trouble.",
+                durationMinute: 20]
+
+        entryResult = taskService.saveEntry(p)
+
+        //Entry #2
+        p = [task: Task.list()[0],
+                entryType: EntryType.get(3),
+                comment: "Cleaned sensor, see how it goes.",
+                durationMinute: 30]
+
+        entryResult = taskService.saveEntry(p)
+
+        //Entry #3
+        p = [task: Task.list()[0],
+                entryType: EntryType.get(3),
+                comment: "Checked up on it later and sensor is dropping out intermittently, created sub task to replace sensor.",
+                durationMinute: 20]
+
+        entryResult = taskService.saveEntry(p)
+
+        //Entry #4
+        p = [task: Task.list()[4],
+                entryType: EntryType.get(3),
+                comment: "Work done as per procedure.",
+                durationMinute: 55]
+
+        entryResult = taskService.saveEntry(p)
+    }
+
+    def createDemoAssignedGroups() {
+
+        def result
+        def p = [:]
+
+        //AssignedGroup #1
+        p = [personGroup: PersonGroup.get(1),
+                task: Task.list()[0],
+                estimatedHour: 2,
+                estimatedMinute: 30]
+        result = assignedGroupService.save(p)
+
+        //AssignedGroup #2
+        p = [personGroup: PersonGroup.get(2),
+                task: Task.list()[0],
+                estimatedHour: 1,
+                estimatedMinute: 0]
+        result = assignedGroupService.save(p)
+    }
+
+    def createDemoAssignedPersons() {
+
+        def result
+        def p = [:]
+
+        //AssignedPerson #1
+        p = [person: Person.get(3), // Demo Manager.
+                task: Task.list()[5],
+                estimatedHour: 1,
+                estimatedMinute: 20]
+        result = assignedPersonService.save(p)
+
+        //AssignedPerson #2
+        p = [person: Person.get(4), // Demo User.
+                task: Task.list()[5],
+                estimatedHour: 1,
+                estimatedMinute: 20]
+        result = assignedPersonService.save(p)
+
+        //AssignedPerson #3
+        p = [person: Person.get(3), // Demo Manager.
+                task: Task.list()[6],
+                estimatedHour: 3,
+                estimatedMinute: 30]
+        result = assignedPersonService.save(p)
+
+        //AssignedPerson #4
+        p = [person: Person.get(4), // Demo User.
+                task: Task.list()[6],
+                estimatedHour: 3,
+                estimatedMinute: 30]
+        result = assignedPersonService.save(p)
+    }
+
+    def createBaseMaintenancePolicies() {
+
+        //MaintenancePolicy
+        def maintenancePolicyInstance
+
+        //MaintenancePolicy #1
+        maintenancePolicyInstance = new MaintenancePolicy(name: "Fixed Time")
+        saveAndTest(maintenancePolicyInstance)
+
+        //MaintenancePolicy #2
+        maintenancePolicyInstance = new MaintenancePolicy(name: "Condition Based Online")
+        saveAndTest(maintenancePolicyInstance)
+
+        //MaintenancePolicy #3
+        maintenancePolicyInstance = new MaintenancePolicy(name: "Condition Based Offline")
+        saveAndTest(maintenancePolicyInstance)
+
+        //MaintenancePolicy #4
+        maintenancePolicyInstance = new MaintenancePolicy(name: "Design Out")
+        saveAndTest(maintenancePolicyInstance)
+
+        //MaintenancePolicy #5
+        maintenancePolicyInstance = new MaintenancePolicy(name: "Operate To Failure")
+        saveAndTest(maintenancePolicyInstance)
+
+        //MaintenancePolicy #6
+        maintenancePolicyInstance = new MaintenancePolicy(name: "Regulatory Requirement")
+        saveAndTest(maintenancePolicyInstance)
+
+        //MaintenancePolicy #7
+        maintenancePolicyInstance = new MaintenancePolicy(name: "Hidden Function Test")
+        saveAndTest(maintenancePolicyInstance)
+    }
+
+    def createDemoTaskProcedure() {
+
+        //TaskProcedure
+        def taskProcedureInstance
+        def taskInstance
+        def person = Person.get(3)
+
+        taskInstance = Task.list()[6]
+        taskProcedureInstance = new TaskProcedure(linkedTask: taskInstance,
+                                                                                    createdBy: person,
+                                                                                    lastUpdatedBy: person)
+        saveAndTest(taskProcedureInstance)
+        taskProcedureInstance.addToTasks(taskInstance)
+
+        taskInstance = Task.list()[4]
+        taskProcedureInstance = new TaskProcedure(linkedTask: taskInstance,
+                                                                                    createdBy: person,
+                                                                                    lastUpdatedBy: person)
+        saveAndTest(taskProcedureInstance)
+        taskProcedureInstance.addToTasks(taskInstance)
+    }
+
+    def createDemoMaintenanceActions() {
+
+        //MaintenanceAction
+        def maintenanceActionInstance
+        def taskProcedure = TaskProcedure.get(1)
+        def assetSubItem = AssetSubItem.get(6)
+
+        //MaintenanceAction #1
+        maintenanceActionInstance = new MaintenanceAction(description: "Check all E-stops, activate E-stops S1-S12 and ensure machine cannot run",
+                                                                                                        procedureStepNumber: 10,
+                                                                                                        assetSubItem: assetSubItem,
+                                                                                                        taskProcedure: taskProcedure)
+        taskProcedure.addToMaintenanceActions(maintenanceActionInstance)
+
+        //MaintenanceAction #2
+        maintenanceActionInstance = new MaintenanceAction(description: "Do more pushups",
+                                                                                                        procedureStepNumber: 20,
+                                                                                                        assetSubItem: assetSubItem,
+                                                                                                        taskProcedure: taskProcedure)
+        taskProcedure.addToMaintenanceActions(maintenanceActionInstance)
+
+        //MaintenanceAction #3
+        maintenanceActionInstance = new MaintenanceAction(description: "Ok just one more pushup",
+                                                                                                        procedureStepNumber: 30,
+                                                                                                        assetSubItem: assetSubItem,
+                                                                                                        taskProcedure: taskProcedure)
+        taskProcedure.addToMaintenanceActions(maintenanceActionInstance)
+
+        saveAndTest(taskProcedure)
+    }
+
+    def createDemoTaskRecurringSchedules() {
+
+        //TaskRecurringSchedule
+        def taskRecurringScheduleInstance
+
+        //TaskRecurringSchedule #1
+        taskRecurringScheduleInstance = new TaskRecurringSchedule(task: Task.list()[0],
+                                                                                                    recurEvery: 1,
+                                                                                                    recurPeriod: Period.get(2),
+                                                                                                    nextTargetStartDate: dateUtilService.today,
+                                                                                                    generateAhead: 1,
+                                                                                                    taskDuration: 2,
+                                                                                                    taskDurationPeriod: Period.get(1),
+                                                                                                    enabled: false)
+        saveAndTest(taskRecurringScheduleInstance)
+
+        //TaskRecurringSchedule #2
+        taskRecurringScheduleInstance = new TaskRecurringSchedule(task: Task.list()[5],
+                                                                                                    recurEvery: 1,
+                                                                                                    recurPeriod: Period.get(1),
+                                                                                                    nextTargetStartDate: dateUtilService.today,
+                                                                                                    generateAhead: 1,
+                                                                                                    taskDuration: 1,
+                                                                                                    taskDurationPeriod: Period.get(1),
+                                                                                                    enabled: true)
+        saveAndTest(taskRecurringScheduleInstance)
+
+        //TaskRecurringSchedule #3
+        taskRecurringScheduleInstance = new TaskRecurringSchedule(task: Task.list()[6],
+                                                                                                    recurEvery: 1,
+                                                                                                    recurPeriod: Period.get(1),
+                                                                                                    nextTargetStartDate: dateUtilService.today,
+                                                                                                    generateAhead: 1,
+                                                                                                    taskDuration: 1,
+                                                                                                    taskDurationPeriod: Period.get(1),
+                                                                                                    enabled: true)
+        saveAndTest(taskRecurringScheduleInstance)
+    }
+
+/*************************
+START OF INVENTORY
+**************************/
+
+    def createDemoInventoryStores() {
+
+        //InventoryStore
+        def inventoryStoreInstance
+
+        inventoryStoreInstance = new InventoryStore(site: Site.get(1), name: "Store #1")
+        saveAndTest(inventoryStoreInstance)
+
+        inventoryStoreInstance = new InventoryStore(site: Site.get(2), name: "Store #2")
+        saveAndTest(inventoryStoreInstance)
+    }
+
+    def createDemoInventoryLocations() {
+
+        // InventoryLocation
+        def inventoryLocation
+
+        inventoryLocation = new InventoryLocation(inventoryStore: InventoryStore.get(1), name: "A1-2")
+        saveAndTest(inventoryLocation)
+
+        inventoryLocation = new InventoryLocation(inventoryStore: InventoryStore.get(2), name: "C55")
+        saveAndTest(inventoryLocation)
+    }
+
+    def createDemoInventoryGroups() {
+
+        //InventoryGroup
+        def inventoryGroupInstance
+
+        //InventoryGroup #1
+        inventoryGroupInstance = new InventoryGroup(name: "Misc")
+        saveAndTest(inventoryGroupInstance)
+
+        //InventoryGroup #2
+        inventoryGroupInstance = new InventoryGroup(name: "Electrical")
+        saveAndTest(inventoryGroupInstance)
+
+        //InventoryGroup #3
+        inventoryGroupInstance = new InventoryGroup(name: "Mechanical")
+        saveAndTest(inventoryGroupInstance)
+
+        //InventoryGroup #4
+        inventoryGroupInstance = new InventoryGroup(name: "Production")
+        saveAndTest(inventoryGroupInstance)
+    }
+
+    def createBaseInventoryTypes() {
+
+        //InventoryType
+        def inventoryTypeInstance
+
+        //InventoryType #1
+        inventoryTypeInstance = new InventoryType(name: "Consumable",
+                                                                                description: "Standard inventory items that are received as new.")
+        saveAndTest(inventoryTypeInstance)
+
+        //InventoryType #2
+        inventoryTypeInstance = new InventoryType(name: "Rotable",
+                                                                                description: "Repairable inventory items that are to be tracked as rotables.")
+        saveAndTest(inventoryTypeInstance)
+
+        //InventoryType #3
+        inventoryTypeInstance = new InventoryType(name: "Service",
+                                                                                description: "Provided services from contractors etc.")
+        saveAndTest(inventoryTypeInstance)
+
+        //InventoryType #4
+        inventoryTypeInstance = new InventoryType(name: "Tool",
+                                                                                description: "Tools that are held as inventory.")
+        saveAndTest(inventoryTypeInstance)
+    }
+
+    def createBaseInventoryMovementTypes() {
+
+        // InventoryMovementType
+        def inventoryMovementTypeInstance
+
+        // InventoryMovementType #1
+        inventoryMovementTypeInstance = new InventoryMovementType(name: "Used",
+                                                                                                                        incrementsInventory: false)
+        saveAndTest(inventoryMovementTypeInstance)
+
+        // InventoryMovementType #2
+        inventoryMovementTypeInstance = new InventoryMovementType(name: "Repaired",
+                                                                                                                        incrementsInventory: true)
+        saveAndTest(inventoryMovementTypeInstance)
+
+        // InventoryMovementType #3
+        inventoryMovementTypeInstance = new InventoryMovementType(name: "Purchase Received",
+                                                                                                                        incrementsInventory: true)
+        saveAndTest(inventoryMovementTypeInstance)
+
+        // InventoryMovementType #4
+        inventoryMovementTypeInstance = new InventoryMovementType(name: "Correction Increase",
+                                                                                                                        incrementsInventory: true)
+        saveAndTest(inventoryMovementTypeInstance)
+
+        // InventoryMovementType #5
+        inventoryMovementTypeInstance = new InventoryMovementType(name: "Correction Decrease",
+                                                                                                                        incrementsInventory: false)
+        saveAndTest(inventoryMovementTypeInstance)
+    }
+
+    def createDemoInventoryItems() {
+
+        //InventoryItem
+        def inventoryItemInstance
+        def currency = Currency.getInstance('AUD')
+
+        def pictureResource = grailsApplication.mainContext.getResource('images/logo.png')
+
+        //InventoryItem #1
+        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(1),
+                                                                                    inventoryType: InventoryType.get(1),
+                                                                                    unitOfMeasure: UnitOfMeasure.get(2),
+                                                                                    inventoryLocation: InventoryLocation.get(1),
+                                                                                    name: "Hemp rope",
+                                                                                    description: "Natural hemp rope.",
+                                                                                    estimatedUnitPriceAmount: 1.23,
+                                                                                    estimatedUnitPriceCurrency: currency,
+                                                                                    unitsInStock: 2,
+                                                                                    reorderPoint: 0)
+        saveAndTest(inventoryItemInstance)
+        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)
+
+        //InventoryItem #2
+        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(1),
+                                                                                    inventoryType: InventoryType.get(1),
+                                                                                    unitOfMeasure: UnitOfMeasure.get(2),
+                                                                                    inventoryLocation: InventoryLocation.get(1),
+                                                                                    name: "Cotton Rope 12mm",
+                                                                                    description: "A soft natural rope made from cotton.",
+                                                                                    estimatedUnitPriceAmount: 2.50,
+                                                                                    estimatedUnitPriceCurrency: currency,
+                                                                                    unitsInStock: 2,
+                                                                                    reorderPoint: 0)
+        saveAndTest(inventoryItemInstance)
+        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)
+
+        //InventoryItem #3
+        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(3),
+                                                                                    inventoryType: InventoryType.get(1),
+                                                                                    unitOfMeasure: UnitOfMeasure.get(1),
+                                                                                    inventoryLocation: InventoryLocation.get(2),
+                                                                                    name: "2305-2RS",
+                                                                                    description: "Bearing 25x62x24mm double row self aligning ball",
+                                                                                    estimatedUnitPriceAmount: 5,
+                                                                                    estimatedUnitPriceCurrency: currency,
+                                                                                    unitsInStock: 3,
+                                                                                    reorderPoint: 2)
+        saveAndTest(inventoryItemInstance)
+        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)
+
+        //InventoryItem #4
+        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(2),
+                                                                                    inventoryType: InventoryType.get(1),
+                                                                                    unitOfMeasure: UnitOfMeasure.get(1),
+                                                                                    inventoryLocation: InventoryLocation.get(2),
+                                                                                    name: "L1592-K10",
+                                                                                    description: "10kW contactor",
+                                                                                    estimatedUnitPriceAmount: 180,
+                                                                                    estimatedUnitPriceCurrency: currency,
+                                                                                    unitsInStock: 4,
+                                                                                    reorderPoint: 0)
+        saveAndTest(inventoryItemInstance)
+        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)
+
+        //InventoryItem #5
+        inventoryItemInstance = new InventoryItem(inventoryGroup: InventoryGroup.get(3),
+                                                                                    inventoryType: InventoryType.get(1),
+                                                                                    unitOfMeasure: UnitOfMeasure.get(1),
+                                                                                    inventoryLocation: InventoryLocation.get(2),
+                                                                                    name: "6205-ZZ",
+                                                                                    description: "Bearing 25x52x15mm single row ball shielded",
+                                                                                    estimatedUnitPriceAmount: 3.45,
+                                                                                    estimatedUnitPriceCurrency: currency,
+                                                                                    unitsInStock: 5,
+                                                                                    reorderPoint: 2)
+        saveAndTest(inventoryItemInstance)
+        inventoryItemService.savePicture(inventoryItemInstance, pictureResource)
+    }
+
+/*******************
+START OF ASSET
+*******************/
+
+    def createBaseExtenededAttributeTypes() {
+
+        //ExtendedAttributeType
+        def extendedAttributeTypeInstance
+
+        //ExtendedAttributeType #1
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Model Number")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #2
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Purchase Cost")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #3
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Serial Number")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #4
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Manufactured Date")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #5
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Location Description")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #6
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Cost Centre")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #7
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Cost Code")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #8
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Manufacturer")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #9
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "ecr")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #10
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Risk Level")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #11
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Safe Work Procedure")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #12
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Regulatory Requirement")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #13
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Maintenance % Completion")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #14
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Registration Required")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #15
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Registration Expiry Date")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #16
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Asset Condition")
+        saveAndTest(extendedAttributeTypeInstance)
+
+        //ExtendedAttributeType #17
+        extendedAttributeTypeInstance = new ExtendedAttributeType(name: "Asset Number")
+        saveAndTest(extendedAttributeTypeInstance)
+    }
+
+    def createDemoSections() {
+
+        //Section
+        def sectionInstance
+
+        //Section #1
+        sectionInstance = new Section(name: "A-Press",
+                                                                description: "Press Section",
+                                                                site: Site.get(3),
+                                                                department: Department.get(1))
+        saveAndTest(sectionInstance)
+
+        //Section #2
+        sectionInstance = new Section(name: "CSM-Delig",
+                                                                description: "Pulp Delignification",
+                                                                site: Site.get(1),
+                                                                department: Department.get(2))
+        saveAndTest(sectionInstance)
+
+        //Section #3
+        sectionInstance = new Section(name: "CSM-Aux",
+                                                                description: "Auxilliary Section",
+                                                                site: Site.get(1),
+                                                                department: Department.get(1))
+        saveAndTest(sectionInstance)
+    }
+
+    def createDemoAssetTree() {
+
+        //Asset
+        def assetInstance
+
+        //Asset #1
+        def assetInstance1 = new Asset(name: "Print Tower 22",
+                                                                description: "Complete Printing Asset #22",
+                                                                comment: "Includes everthing directly attached to the tower.",
+                                                                section: Section.get(1))
+        saveAndTest(assetInstance1)
+
+        //Asset #2
+        def assetInstance2 = new Asset(name: "Print Tower 21",
+                                                                description: "Complete Printing Asset #21",
+                                                                section: Section.get(1))
+        saveAndTest(assetInstance2)
+
+        //Asset #3
+        def assetInstance3 = new Asset(name: "Print Tower 23",
+                                                                description: "Complete Printing Asset #23",
+                                                                section: Section.get(1))
+        saveAndTest(assetInstance3)
+
+        //Asset #4
+        def assetInstance4 = new Asset(name: "C579",
+                                                                description: "RO #1",
+                                                                section: Section.get(2))
+        saveAndTest(assetInstance4)
+
+        //AssetSubItem
+        def assetSubItemInstance
+
+        //AssetSubItem #1 Level1
+        def assetSubItemInstance1 = new AssetSubItem(name: "Print Tower",
+                                                                                            description: "Common sub asset.")
+        saveAndTest(assetSubItemInstance1)
+
+        // Add assetSubItemInstance1 to some assets.
+        assetInstance1.addToAssetSubItems(assetSubItemInstance1)
+        assetInstance2.addToAssetSubItems(assetSubItemInstance1)
+        assetInstance3.addToAssetSubItems(assetSubItemInstance1)
+
+        //AssetSubItem #2 Level1
+        def assetSubItemInstance2 = new AssetSubItem(name: "C579-44",
+                                                                                            description: "Tanks and towers")
+        saveAndTest(assetSubItemInstance2)
+
+        // Add assetSubItemInstance2 to some assets.
+        assetInstance4.addToAssetSubItems(assetSubItemInstance2)
+
+        //AssetSubItem #3 Level1
+        def assetSubItemInstance3 = new AssetSubItem(name: "C579-20",
+                                                                                            description: "Control Loops")
+        saveAndTest(assetSubItemInstance3)
+
+        // Add assetSubItemInstance3 to some assets.
+        assetInstance4.addToAssetSubItems(assetSubItemInstance3)
+
+        //AssetSubItem #4 Level2
+        assetSubItemInstance = new AssetSubItem(name: "C579-TK-0022",
+                                                                                            description: "Blow Tank",
+                                                                                            parentItem: AssetSubItem.get(2))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #5 Level2
+        assetSubItemInstance = new AssetSubItem(name: "C579-TK-0023",
+                                                                                            description: "Reactor Tower",
+                                                                                            parentItem: AssetSubItem.get(2))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #6 Level2
+        assetSubItemInstance = new AssetSubItem(name: "Print Unit",
+                                                                                    description: "Print Unit - Common Level 2 sub item.",
+                                                                                    parentItem: AssetSubItem.get(1))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #7 Level2
+        assetSubItemInstance = new AssetSubItem(name: "1925365",
+                                                                                    description: "Agitator",
+                                                                                    parentItem: AssetSubItem.get(4))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #8 Level2
+        assetSubItemInstance = new AssetSubItem(name: "1925366",
+                                                                                    description: "Scraper",
+                                                                                    parentItem: AssetSubItem.get(4))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #9 Level3
+        assetSubItemInstance = new AssetSubItem(name: "Motor",
+                                                                                    description: "Motor - Level 3 sub item",
+                                                                                    parentItem: AssetSubItem.get(6))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #10 Level3
+        assetSubItemInstance = new AssetSubItem(name: "Gearbox",
+                                                                                    description: "Gearbox - Level 3 sub item, gearbox",
+                                                                                    parentItem: AssetSubItem.get(6))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #11 Level4
+        assetSubItemInstance = new AssetSubItem(name: "DS Bearing",
+                                                                                    description: "Drive Side Bearing",
+                                                                                    parentItem: AssetSubItem.get(9))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #12 Level4
+        assetSubItemInstance = new AssetSubItem(name: "NDS Bearing",
+                                                                                    description: "Non Drive Side Bearing",
+                                                                                    parentItem: AssetSubItem.get(9))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #13 Level2
+        assetSubItemInstance = new AssetSubItem(name: "C579-F-0001",
+                                                                                    description: "Weak Caustic Flow",
+                                                                                    parentItem: AssetSubItem.get(3))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #14 Level3
+        assetSubItemInstance = new AssetSubItem(name: "C579-FT-0002",
+                                                                                    description: "Weak Caustic Flow Transmitter",
+                                                                                    parentItem: AssetSubItem.get(13))
+        saveAndTest(assetSubItemInstance)
+
+        //AssetSubItem #15 Level3
+        assetSubItemInstance = new AssetSubItem(name: "C579-PT-0003",
+                                                                                    description: "Weak Caustic Pressure Transmitter",
+                                                                                    parentItem: AssetSubItem.get(13))
+        saveAndTest(assetSubItemInstance)
+    } // createDemoAssetTree()
+
+    def createDemoAssetSubItemExtendedAttributes() {
+
+        //AssetSubItemExtendedAttribute
+        def assetSubItemExtendedAttributeInstance
+
+        //AssetSubItemExtendedAttribute #1
+        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "United Press",
+                                                                                                                    assetSubItem: AssetSubItem.get(1),
+                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(8)) // Manufacturer.
+        saveAndTest(assetSubItemExtendedAttributeInstance)
+
+        //AssetSubItemExtendedAttribute #2
+        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "PU Mark 2",
+                                                                                                                    assetSubItem: AssetSubItem.get(1),
+                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(1)) // Model Number.
+        saveAndTest(assetSubItemExtendedAttributeInstance)
+
+        //AssetSubItemExtendedAttribute #3
+        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "765895",
+                                                                                                                    assetSubItem: AssetSubItem.get(1),
+                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(3)) // Serial Number.
+        saveAndTest(assetSubItemExtendedAttributeInstance)
+
+        //AssetSubItemExtendedAttribute #4
+        assetSubItemExtendedAttributeInstance = new AssetSubItemExtendedAttribute(value: "Jan-2003",
+                                                                                                                    assetSubItem: AssetSubItem.get(1),
+                                                                                                                    extendedAttributeType: ExtendedAttributeType.get(4)) // Manufactured Date.
+        saveAndTest(assetSubItemExtendedAttributeInstance)
+
+    }
+
+    def createDemoAssetExtendedAttributes() {
+
+        //AssetExtendedAttribute
+        def assetExtendedAttributeInstance
+
+        //AssetExtendedAttribute #1
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "On the far side of Tank 5",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(5)) // Location Description.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #2
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "3",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(9)) // ecr.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #3
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "RP-001",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(17)) // Asset Number.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #4
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Good",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(16)) // Asset Condition.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #5
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "TBA",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(13)) // Maintenance % Completion.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #6
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Y",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(14)) // Registration Required.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #7
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Feb-2009",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(15)) // Registration Expiry Date.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #8
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "N",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(12)) // Regulatory Requirement.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #9
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "Med",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(10)) // Risk Level.
+        saveAndTest(assetExtendedAttributeInstance)
+
+        //AssetExtendedAttribute #10
+        assetExtendedAttributeInstance = new AssetExtendedAttribute(value: "WP-003",
+                                                                                                            asset: Asset.get(1),
+                                                                                                            extendedAttributeType: ExtendedAttributeType.get(11)) // Safe Work Procedure.
+        saveAndTest(assetExtendedAttributeInstance)
+    }
+
+    /**
+    * SearchableIndex and mirroring is disabled at startup.
+    * Use this to start indexing after creating bootstrap data.
+    * @param indexInNewThread Whether to run the index in a new thread, defaults to true.
+    */
+    def startSearchableIndex(Boolean indexInNewThread = true) {
+        log.info "Start mirroring searchable index."
+        ConfigurationHolder.config.appSearchable.cascadeOnUpdate = true
+        searchableService.startMirroring()
+        if(indexInNewThread) {
+            Thread.start {
+                log.info "Rebuilding searchable index, bulkIndex (new thread)."
+                searchableService.index()
+                log.info "Rebuilding searchable index, complete."
+            }
+        }
+        else {
+            log.info "Rebuilding searchable index, bulkIndex."
+            searchableService.index()
+            log.info "Rebuilding searchable index, complete."
+        }
+    }
+
+    /**
+    * Searchable index and mirroring during bulk data creation may be slow.
+    * Use this to stop indexing and restart with startSearchableIndex() after data creation.
+    */
+    def stopSearchableIndex() {
+        log.info "Stop mirroring searchable index."
+        ConfigurationHolder.config.appSearchable.cascadeOnUpdate = false
+        searchableService.stopMirroring()
+    }
+
+    /**
+    * Call this function instead of .save()
+    */
+    private boolean saveAndTest(object) {
+        if(!object.save()) {
+//             DemoDataSuccessful = false
+            log.error "'${object}' failed to save!"
+            log.error object.errors
+            return false
+        }
+        return true
+    }
+
+} // end of class
Index: /branches/features/grailsUpgrade/grails-app/services/DateUtilService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/DateUtilService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/DateUtilService.groovy	(revision 875)
@@ -0,0 +1,165 @@
+import org.codehaus.groovy.runtime.TimeCategory
+// the above will be deprecated and replaced by: groovy.time.TimeCategory
+/// @todo: consider moving this to org.gnumims.DateUtil
+/// pros: easy to use in domain classes.
+/// cons: have to import so pulls in all referenced imports? Injection probably does that anyway.
+
+/**
+* Provides some convenience methods for working with dates.
+*/
+class DateUtilService {
+
+    boolean transactional = false
+    //static scope = "request"
+
+    /**
+    * Get the start of today.
+     * Can be call as dateUtilService.today or dateUtilService.getToday().
+     * @returns A Date object with today's date and all time fields set to 0.
+    */
+    public static Date getToday() {
+        return getMidnight(new Date())
+    }
+
+    /**
+    * Get the start of tomorrow.
+     * Can be call as dateUtilService.tomorrow or dateUtilService.getTomorrow().
+     * @returns A Date object with tomorrow's date and all time fields set to 0.
+    */
+    public static Date getTomorrow() {
+        return (getToday() + 1) as Date
+    }
+
+    /**
+    * Get the start of yesterday.
+     * Can be call as dateUtilService.yesterday or dateUtilService.getYesterday().
+     * @returns A Date object with yesterday's date and all time fields set to 0.
+    */
+    public static Date getYesterday() {
+        return (getToday() - 1) as Date
+    }
+
+    /**
+    * Get the start of the day one week ago.
+     * Can be call as dateUtilService.oneWeekAgo or dateUtilService.getOneWeekAgo().
+     * @returns A Date object with the date one week ago and all time fields set to 0.
+    */
+    public static Date getOneWeekAgo() {
+        return (getToday() - 7) as Date
+    }
+
+    /**
+    * Get the start of the day one week ago.
+     * Can be call as dateUtilService.oneWeekAgo or dateUtilService.getOneWeekAgo().
+     * @returns A Date object with the date one week ago and all time fields set to 0.
+    */
+    public static Date getOneWeekFromNow() {
+        return (getToday() + 7) as Date
+    }
+
+    /**
+    * Get the start of a given date by setting all time fields to 0.
+    * The Calendar.getInstance() or Calendar.instance factory returns a new calendar instance, usually
+    * a Gregorian calendar but using Calendar we don't have to worry about those details.
+    * The time fields are then set to zero and cal.getTime() or cal.time returns a java.util.Date object.
+    * @param date The Date object to start with.
+    * @returns A Date object having the given date and all time fields set to 0, so the very start of the given day.
+    */
+    public static Date getMidnight(Date date) {
+        Calendar cal = Calendar.instance
+        cal.setTime(date)
+        cal.set(Calendar.HOUR_OF_DAY, 0)
+        cal.set(Calendar.MINUTE, 0)
+        cal.set(Calendar.SECOND, 0)
+        cal.set(Calendar.MILLISECOND, 0)
+        cal.time
+    }
+
+    /**
+    * Get the date plus x weeks.
+    * @param date The Date object to start with, defaults to today.
+    * @param plusYears The number of weeks to add, defaults to 1.
+    * @returns A Date object adjusted by x weeks.
+    */
+    public static Date plusWeek(Date date = new Date(), Integer plusWeeks = 1) {
+        use(TimeCategory) {
+            date + plusWeeks.weeks
+        }
+    }
+
+    /**
+    * Get the date plus x months.
+    * @param date The Date object to start with, defaults to today.
+    * @param plusYears The number of months to add, defaults to 1.
+    * @returns A Date object adjusted by x months.
+    */
+    public static Date plusMonth(Date date = new Date(), Integer plusMonths = 1) {
+        use(TimeCategory) {
+            date + plusMonths.months
+        }
+    }
+
+    /**
+    * Get the date plus x years.
+    * @param date The Date object to start with, defaults to today.
+    * @param plusYears The number of years to add, defaults to 1.
+    * @returns A Date object adjusted by x years.
+    */
+    public static Date plusYear(Date date = new Date(), Integer plusYears = 1) {
+        use(TimeCategory) {
+            date + plusYears.years
+        }
+    }
+
+    /**
+    * Make a date object from supplied year, month, day values.
+    * The Calendar.getInstance() or Calendar.instance factory returns a new calendar instance, usually
+    * a Gregorian calendar but using Calendar we don't have to worry about those details.
+    * The time fields are set to zero and cal.getTime() or cal.time returns a java.util.Date object.
+    * @param year The year as a string or integer.
+    * @param month The month as a string or integer, defaults to 1 (i.e. January).
+    * @param day The day as a string or integer, defaults to 1.
+    * @returns A Date object having the given date and all time fields set to 0, so the very start of the given day.
+    */
+    public static Date makeDate(year, month=1, day=1) {
+        Calendar cal = Calendar.instance
+        cal.clear()
+        // Stupid month is 0-based, grumble.
+        cal.set(year.toInteger(), month.toInteger()-1, day.toInteger())
+        cal.time
+    }
+
+    /**
+    * Get the day of month from supplied date.
+    * @param date The date to extract the day of month from.
+    * @returns An integer representing the day of the month.
+    */
+    public static Integer getDayOfMonthFromDate(Date date) {
+        Calendar cal = Calendar.instance
+        cal.setTime(date)
+        cal.get(Calendar.DAY_OF_MONTH)
+    }
+
+    /**
+    * Get the month from supplied date.
+    * @param date The date to extract the month from.
+    * @returns An integer representing the month.
+    */
+    public static Integer getMonthFromDate(Date date) {
+        Calendar cal = Calendar.instance
+        cal.setTime(date)
+        cal.get(Calendar.MONTH) + 1 // Stupid month is 0-based, grumble.
+    }
+
+    /**
+    * Get the year from supplied date.
+    * @param date The date to extract the year from.
+    * @returns An integer representing the year.
+    */
+    public static Integer getYearFromDate(Date date) {
+        Calendar cal = Calendar.instance
+        cal.setTime(date)
+        cal.get(Calendar.YEAR)
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/InventoryCsvService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/InventoryCsvService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/InventoryCsvService.groovy	(revision 875)
@@ -0,0 +1,718 @@
+import grails.util.GrailsUtil
+import au.com.bytecode.opencsv.CSVWriter
+import au.com.bytecode.opencsv.CSVReader
+import org.apache.commons.lang.WordUtils
+
+/**
+ * Provides some csv import/export methods.
+ * Requires the opencsv jar to be available which is included in the grails-export plugin.
+ */
+class InventoryCsvService {
+
+    boolean transactional = false
+
+    def dateUtilService
+    def createDataService
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    def sessionFactory
+    def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
+
+    /**
+    * Import inventory creating items as required.
+    * @param request The http request to run getFile against.
+    * Get file should return a csv format file containing the inventory as per template.
+    */
+    def importInventory(request) {
+        InventoryItem.withTransaction { status ->
+            def result = [:]
+
+            def kByteMultiplier = 1000
+            def fileMaxSize = 800 * kByteMultiplier
+            def logFileLink = g.link(controller: "appCore", action: "appLog") {"log"}
+
+            def multiPartFile = request.getFile('file')
+
+            InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
+            CSVReader reader = new CSVReader(sr)
+
+            // Turn off index mirroring.
+            createDataService.stopSearchableIndex()
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                createDataService.startSearchableIndex() // Start mirroring again and rebuild index.
+                reader.close()
+                result.error = [ code: m.code, args: m.args ]
+                return result
+            }
+
+            if(!multiPartFile || multiPartFile.isEmpty())
+                return fail(code: "default.file.not.supplied")
+
+            if (multiPartFile.getSize() > fileMaxSize)
+                return fail(code: "default.file.over.max.size", args: [fileMaxSize/kByteMultiplier, "kB"])
+
+            def line = []
+            def lineNumber = 0
+            def maxNumberOfColumns = 19
+            def inventoryParams = [:]
+            def inventoryProperties = ["name", "description", "comment", "unitsInStock", "reorderPoint", "reorderQuantity",
+                                                        "unitOfMeasure", "estimatedUnitPriceAmount", "estimatedUnitPriceCurrency",
+                                                        "enableReorderListing", "inventoryLocation", "inventoryStore", "site",
+                                                        "inventoryGroup", "inventoryType",
+                                                        "suppliersPartNumber", "preferredSupplier", "alternateSuppliers",
+                                                        "spareFor"]
+
+            def siteInstance
+            def alternateSupplierInstance
+            def preferredSupplierInstance
+            def supplierTypeInstance
+            def supplierTypeUnknown = SupplierType.get(1)
+            def spareForInstance
+            def inventoryTypeInstance
+            def unitOfMeasureInstance
+            def inventoryGroupInstance
+            def inventoryItemInstance
+            def inventoryStoreInstance
+            def inventoryLocationInstance
+
+            def tempPreferredSupplierItemAndType = ''
+            def tempPreferredSupplierItem = ''
+            def tempPreferredSupplierType = ''
+
+            def tempAlternateSuppliers = []
+            def tempSupplierItem = ''
+            def tempSupplierType = ''
+            def tempSupplierItemAndType = []
+
+            def tempSpareFor = []
+
+            def nextLine = {
+                    line = reader.readNext()
+                    lineNumber ++
+                    log.info "Processing line: " + lineNumber
+            }
+
+            def parseInputList = {
+                if( (it == null) || (it.trim() == '') ) return []
+                return it.split(";").collect{it.trim()}
+            }
+
+            def parseItemAndType = {
+                return it.split("@").collect{it.trim()}
+            }
+
+            // Get first line.
+            nextLine()
+
+            // Check for header line 1.
+            if(line != templateHeaderLine1) {
+                log.error "Failed to find header line 1. "
+                log.error "Required: " + templateHeaderLine1.toString()
+                log.error "Supplied: " + line.toString()
+                return fail(code: "default.file.no.header")
+            }
+
+            log.info "Header line found."
+
+            // Prepare the first body line.
+            nextLine()
+
+            // Primary loop.
+            while(line) {
+
+                if(line.size() > maxNumberOfColumns) {
+                    log.error "Too many columns on line: " + lineNumber
+                    return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                }
+
+                // Ignore comment lines.
+                if(line.toString().toLowerCase().contains("comment")) {
+                    log.info "Comment line found."
+                    nextLine()
+                    continue
+                }
+
+                // Ignore example lines.
+                if(line.toString().toLowerCase().contains("example")) {
+                    log.info "Example line found."
+                    nextLine()
+                    continue
+                }
+
+                // Parse the line into the params map.
+                inventoryParams = [:]
+                line.eachWithIndex { it, j ->
+                    inventoryParams."${inventoryProperties[j]}" = it.trim()
+                }
+
+                // Debug
+                log.debug " Supplied params: "
+                log.debug inventoryParams
+
+                // Ignore blank lines.
+                if(inventoryParams.name == '') {
+                    log.info "No name found."
+                    nextLine()
+                    continue
+                }
+
+                /** Prepare the params and create supporting items as required. */
+
+                // Site
+                inventoryParams.site = WordUtils.capitalize(inventoryParams.site)
+                siteInstance = Site.findByName(inventoryParams.site)
+                if(!siteInstance) {
+                    siteInstance = new Site(name: inventoryParams.site)
+                    if(!siteInstance.save()) {
+                        log.error "Failed to create site on line: " + lineNumber
+                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+
+                // InventoryStore
+                inventoryParams.inventoryStore = WordUtils.capitalizeFully(inventoryParams.inventoryStore)
+                inventoryStoreInstance = InventoryStore.findByName(inventoryParams.inventoryStore)
+                if(!inventoryStoreInstance) {
+                    inventoryStoreInstance = new InventoryStore(name: inventoryParams.inventoryStore,
+                                                                                                site: siteInstance)
+                    if(!inventoryStoreInstance.save()) {
+                        log.error "Failed to create inventory store on line: " + lineNumber
+                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+
+                // InventoryLocation
+                inventoryParams.inventoryLocation = WordUtils.capitalize(inventoryParams.inventoryLocation)
+                inventoryLocationInstance = InventoryLocation.findByName(inventoryParams.inventoryLocation)
+                if(!inventoryLocationInstance) {
+                    inventoryLocationInstance = new InventoryLocation(name: inventoryParams.inventoryLocation,
+                                                                                                        inventoryStore: inventoryStoreInstance)
+                    if(!inventoryLocationInstance.save()) {
+                        log.error "Failed to create inventory location on line: " + lineNumber
+                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+
+                // InventoryGroup
+                inventoryParams.inventoryLocation = WordUtils.capitalizeFully(inventoryParams.inventoryLocation)
+                inventoryGroupInstance = InventoryGroup.findByName(inventoryParams.inventoryGroup)
+                if(!inventoryGroupInstance) {
+                    inventoryGroupInstance = new InventoryGroup(name: inventoryParams.inventoryGroup)
+                    if(!inventoryGroupInstance.save()) {
+                        log.error "Failed to create inventory group on line: " + lineNumber
+                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+
+                // InventoryType
+                inventoryParams.inventoryType = WordUtils.capitalizeFully(inventoryParams.inventoryType)
+                inventoryTypeInstance = InventoryType.findByName(inventoryParams.inventoryType)
+                if(!inventoryTypeInstance) {
+                    inventoryTypeInstance = new InventoryType(name: inventoryParams.inventoryType)
+                    if(!inventoryTypeInstance.save()) {
+                        log.error "Failed to create inventory type on line: " + lineNumber
+                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+
+                // UnitOfMeasure.
+                unitOfMeasureInstance = UnitOfMeasure.findByName(inventoryParams.unitOfMeasure)
+                if(!unitOfMeasureInstance) {
+                    unitOfMeasureInstance = new UnitOfMeasure(name: inventoryParams.unitOfMeasure)
+                    if(!unitOfMeasureInstance.save()) {
+                        log.error "Failed to create unit of measure on line: " + lineNumber
+                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                    }
+                }
+
+                // Preferred Supplier
+                if(inventoryParams.preferredSupplier) {
+                    tempPreferredSupplierItemAndType = parseItemAndType(inventoryParams.preferredSupplier)
+                    tempPreferredSupplierItem = WordUtils.capitalize(tempPreferredSupplierItemAndType[0])
+
+                    preferredSupplierInstance = Supplier.findByName(tempPreferredSupplierItem)
+                    if(!preferredSupplierInstance) {
+
+                        // SupplierType.
+                        if(tempPreferredSupplierItemAndType.size == 2) {
+                            tempPreferredSupplierType = WordUtils.capitalize(tempPreferredSupplierItemAndType[1])
+                            supplierTypeInstance = SupplierType.findByName(tempPreferredSupplierType)
+                        }
+                        else
+                            supplierTypeInstance = supplierTypeUnknown
+                        if(!supplierTypeInstance) {
+                            log.error "Failed to find preferred supplier type on line: " + lineNumber
+                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                        }
+
+                        preferredSupplierInstance = new Supplier(name: tempPreferredSupplierItem,
+                                                                                            supplierType: supplierTypeInstance)
+                        if(!preferredSupplierInstance.save()) {
+                            log.error "Failed to create preferred supplier on line: " + lineNumber
+                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                        }
+                    }
+                }
+                else
+                    preferredSupplierInstance = null
+
+                // Alternate Suppliers.
+                tempAlternateSuppliers = parseInputList(inventoryParams.alternateSuppliers)
+                inventoryParams.alternateSuppliers = []
+
+                for(tempSupplier in tempAlternateSuppliers) {
+                    tempSupplierItemAndType = parseItemAndType(tempSupplier)
+                    tempSupplierItem = WordUtils.capitalizeFully(tempSupplierItemAndType[0])
+
+                    alternateSupplierInstance = Supplier.findByName(tempSupplierItem)
+                    if(!alternateSupplierInstance) {
+
+                        // SupplierType.
+                        if(tempSupplierItemAndType.size == 2) {
+                            tempSupplierType = WordUtils.capitalize(tempSupplierItemAndType[1])
+                            supplierTypeInstance = SupplierType.findByName(tempSupplierType)
+                        }
+                        else
+                            supplierTypeInstance = supplierTypeUnknown
+                        if(!supplierTypeInstance) {
+                            log.error "Failed to find alternate supplier type on line: " + lineNumber
+                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                        }
+
+                        alternateSupplierInstance = new Supplier(name: tempSupplierItem,
+                                                                            supplierType: supplierTypeInstance)
+                        if(!alternateSupplierInstance.save()) {
+                            log.error "Failed to create alternate suppliers on line: " + lineNumber
+                            return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                        }
+                    }
+
+                    inventoryParams.alternateSuppliers.add(alternateSupplierInstance)
+                }
+
+                // spareFor.
+                tempSpareFor = parseInputList(inventoryParams.spareFor)
+                inventoryParams.spareFor = []
+
+                for(asset in tempSpareFor) {
+
+                    asset = WordUtils.capitalize(asset)
+
+                    spareForInstance = Asset.findByName(asset)
+                    if(!spareForInstance) {
+                        log.error "Failed to find 'Spare For' asset on line: " + lineNumber
+                        return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                    }
+
+                    inventoryParams.spareFor.add(spareForInstance)
+                }
+
+                // Assign the retrieved or created instances to params.
+                inventoryParams.inventoryLocation = inventoryLocationInstance
+                inventoryParams.inventoryGroup = inventoryGroupInstance
+                inventoryParams.inventoryType = inventoryTypeInstance
+                inventoryParams.unitOfMeasure = unitOfMeasureInstance
+                inventoryParams.preferredSupplier = preferredSupplierInstance
+
+                // Name.
+                // Checked above for blank string.
+                inventoryParams.name = WordUtils.capitalize(inventoryParams.name)
+
+                // Description.
+                if(inventoryParams.description != '')
+                    inventoryParams.description = inventoryParams.description[0].toUpperCase() + inventoryParams.description[1..-1]
+
+                // Debug
+                log.debug "InventoryParams: "
+                log.debug inventoryParams
+
+                // Create new or update.
+                inventoryItemInstance = InventoryItem.findByName(inventoryParams.name)
+                if(inventoryItemInstance) {
+                    log.info "Updating existing item: " + inventoryItemInstance
+                    inventoryItemInstance.properties = inventoryParams
+                }
+                else {
+                    log.info "Creating new item: " + inventoryParams.name
+                    inventoryItemInstance = new InventoryItem(inventoryParams)
+                }
+
+                // Save inventoryItem.
+                if(inventoryItemInstance.hasErrors() || !inventoryItemInstance.save()) {
+                    log.error "Failed to create item on line: " + lineNumber
+                    log.debug inventoryItemInstance.errors
+                    return fail(code: "inventory.import.failure", args: [lineNumber, logFileLink])
+                }
+
+                if(lineNumber % 100 == 0)
+                    cleanUpGorm()
+
+                if(!result.error) nextLine()
+            } //while(line)
+
+            // Success.
+            log.info "End of file."
+            createDataService.startSearchableIndex() // Start mirroring again and rebuild index.
+            reader.close()
+            return result
+
+        } //end withTransaction
+    } // end importInventory()
+
+    /**
+    * Build an inventory template csv file.
+    * This template can then be populated for import.
+    * @returns The template as a String in csv format.
+    */
+    def buildInventoryTemplate() {
+
+        StringWriter sw = new StringWriter()
+        CSVWriter writer = new CSVWriter(sw)
+
+        writeTemplateLines(writer)
+
+        writer.close()
+        return sw.toString()
+    }
+
+    private writeTemplateLines(writer) {
+        writer.writeNext(templateHeaderLine1 as String[])
+        writer.writeNext()
+        writer.writeNext("Comment: The header line is required.")
+        writer.writeNext("Comment: Required columns are marked with a (*) in the header line.")
+        writer.writeNext("Comment: Lists of items in a column must be separated by a semicolon (;), not a comma.")
+        writer.writeNext("Comment: The at symbol (@) is reserved for indicating supplier types.")
+        writer.writeNext("Comment: Identical and existing names will be considered as the same item.")
+        writer.writeNext("Comment: Lines containing 'comment' will be ignored.")
+        writer.writeNext("Comment: Lines containing 'example' will be ignored.")
+        writer.writeNext("Comment: This file must be saved as a CSV file before import.")
+        writer.writeNext()
+    }
+
+    /**
+    * Build an inventory example/test file.
+    * This test file can be imported to test the import and export methods.
+    * @returns The test file as a String in csv format.
+    */
+    def buildInventoryExample() {
+
+        StringWriter sw = new StringWriter()
+        CSVWriter writer = new CSVWriter(sw)
+
+        writeTemplateLines(writer)
+
+        // Requires creation of some of the base/group/type data.
+        writer.writeNext(["Split19", "19mm split pin", "Very usefull item.",
+                                        "1024", "0", "1",
+                                        "each", "5", "NZD",
+                                        "false", "BR4",
+                                        "Store #99", "Inventory Depot",
+                                        "Mechanical Stock",
+                                        "Consumable",
+                                        "123", "Multi Supplier@Local",
+                                        "Multi Distributors1@OEM; Multi Distributors2@Local",
+                                        ""
+                                        ] as String[])
+
+        // Using existing base data.
+        writer.writeNext(["2204E-2RS", "Double Row Self Align Ball Bearing 2204E-2RS - Sealed - 20/47x18", "",
+                                        "4", "1", "9",
+                                        "each", "16.35", "USD",
+                                        "TRUE", "BR4",
+                                        "Store #99", "Inventory Depot",
+                                        "Mechanical Stock",
+                                        "Consumable",
+                                        "456KL", "Multi Supplier",
+                                        "Multi Distributors1; Multi Distributors2",
+                                        ""
+                                        ] as String[])
+
+        writer.close()
+        return sw.toString()
+    }
+
+    /**
+    * Build complete inventory for export.
+    * @param inventoryItemList The list of inventory items to build.
+    * @returns The inventory as a String in csv format.
+    */
+    def buildInventory(List inventoryItemList) {
+
+        def sw = new StringWriter()
+        def writer = new CSVWriter(sw)
+
+        writeTemplateLines(writer)
+
+        //Rows
+        def row
+
+        inventoryItemList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { inventoryItem ->
+            row = []
+            row.add(inventoryItem.name)
+            row.add(inventoryItem.description)
+            row.add(inventoryItem.comment)
+            row.add(inventoryItem.unitsInStock)
+            row.add(inventoryItem.reorderPoint)
+            row.add(inventoryItem.reorderQuantity)
+            row.add(inventoryItem.unitOfMeasure)
+            row.add(inventoryItem.estimatedUnitPriceAmount)
+            row.add(inventoryItem.estimatedUnitPriceCurrency)
+            row.add(inventoryItem.enableReorderListing)
+            row.add(inventoryItem.inventoryLocation)
+            row.add(inventoryItem.inventoryLocation.inventoryStore)
+            row.add(inventoryItem.inventoryLocation.inventoryStore.site)
+            row.add(inventoryItem.inventoryGroup)
+            row.add(inventoryItem.inventoryType)
+            row.add(inventoryItem.suppliersPartNumber)
+
+            if(inventoryItem.preferredSupplier)
+                row.add( inventoryItem.preferredSupplier.name + "@" + inventoryItem.preferredSupplier.supplierType )
+            else
+                row.add('')
+
+            row.add( inventoryItem.alternateSuppliers.sort { p1, p2 ->
+                p1.name.compareToIgnoreCase(p2.name)
+            }.collect { it.name + "@" + it.supplierType }.join(';') )
+
+            row.add(inventoryItem.spareFor.sort { p1, p2 ->
+                p1.name.compareToIgnoreCase(p2.name)
+            }.collect { it.name }.join(';'))
+
+            writer.writeNext(row as String[])
+        }
+
+        writer.close()
+        return sw.toString()
+    } // end buildInventory()
+
+    /**
+    * Import inventoryItemPurchases creating items as required.
+    */
+    def importInventoryItemPurchases(request) {
+        InventoryItemPurchase.withTransaction { status ->
+            def result = [:]
+
+            def kByteMultiplier = 1000
+            def fileMaxSize = 800 * kByteMultiplier
+            def logFileLink = g.link(controller: "appCore", action: "appLog") {"log"}
+
+            def multiPartFile = request.getFile('file')
+
+            InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
+            CSVReader reader = new CSVReader(sr)
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                reader.close()
+                result.error = [ code: m.code, args: m.args ]
+                return result
+            }
+
+            if(!multiPartFile || multiPartFile.isEmpty())
+                return fail(code: "default.file.not.supplied")
+
+            if (multiPartFile.getSize() > fileMaxSize)
+                return fail(code: "default.file.over.max.size", args: [fileMaxSize/kByteMultiplier, "kB"])
+
+            def line = []
+            def lineNumber = 0
+            def maxNumberOfColumns = 10
+            def inventoryItemPurchaseParams = [:]
+            def inventoryItemPurchaseProperties = ["inventoryItem", "purchaseOrderNumber", "quantity",
+                                                                                "inventoryItemPurchaseType",
+                                                                                "costCode", "enteredBy", "dateEntered",
+                                                                                "orderValueAmount", "orderValueCurrency", "invoiceNumber"]
+
+            def personInstance
+            def costCodeInstance
+            def inventoryItemInstance
+            def inventoryItemPurchaseInstance
+            def inventoryItemPurchaseTypeInstance
+
+            def nextLine = {
+                    line = reader.readNext()
+                    lineNumber ++
+                    log.info "Processing line: " + lineNumber
+            }
+
+            def parseInputDate = {
+                if( (it == null) || (it.trim() == '') ) {
+                    log.error "Failed to find any date on line: " + lineNumber
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+
+                def d = it.split("/").collect{it.trim()}
+                if(d.size() != 3) {
+                    log.error "Failed to find full date on line: " + lineNumber
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+                dateUtilService.makeDate(d[0], d[1], d[2])
+            }
+
+            // Get first line.
+            nextLine()
+
+            // Check for header line 1.
+            if(line != purchasesTemplateHeaderLine1) {
+                log.error "Failed to find header line 1. "
+                log.error "Required: " + purchasesTemplateHeaderLine1.toString()
+                log.error "Supplied: " + line.toString()
+                return fail(code: "default.file.no.header")
+            }
+
+            log.info "Header line found."
+
+            // Prepare the first body line.
+            nextLine()
+
+            // Primary loop.
+            while(line) {
+
+                if(line.size() > maxNumberOfColumns) {
+                    log.error "Too many columns on line: " + lineNumber
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+
+                // Ignore comment lines.
+                if(line.toString().toLowerCase().contains("comment")) {
+                    log.info "Comment line found."
+                    nextLine()
+                    continue
+                }
+
+                // Ignore example lines.
+                if(line.toString().toLowerCase().contains("example")) {
+                    log.info "Example line found."
+                    nextLine()
+                    continue
+                }
+
+                // Parse the line into the params map.
+                inventoryItemPurchaseParams = [:]
+                line.eachWithIndex { it, j ->
+                    inventoryItemPurchaseParams."${inventoryItemPurchaseProperties[j]}" = it.trim()
+                }
+
+                // Debug
+                log.debug " Supplied params: "
+                log.debug inventoryItemPurchaseParams
+
+                // Ignore blank lines.
+                if(inventoryItemPurchaseParams.inventoryItem == '') {
+                    log.info "No inventory item name found."
+                    nextLine()
+                    continue
+                }
+
+                // Inventory Item.
+                inventoryItemPurchaseParams.inventoryItem = WordUtils.capitalize(inventoryItemPurchaseParams.inventoryItem)
+                inventoryItemInstance = InventoryItem.findByName(inventoryItemPurchaseParams.inventoryItem)
+                if(!inventoryItemInstance) {
+                    log.error "Inventory item not found on line: " + lineNumber
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+                inventoryItemPurchaseParams.inventoryItem = inventoryItemInstance
+
+                // Quantity.
+                if(inventoryItemPurchaseParams.quantity.isInteger())
+                    inventoryItemPurchaseParams.quantity = inventoryItemPurchaseParams.quantity.toInteger()
+                else {
+                    log.error "Quantity is not a valid number on line: " + lineNumber
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+
+                // InventoryItemPurchaseType.
+                inventoryItemPurchaseParams.inventoryItemPurchaseType = WordUtils.capitalizeFully(inventoryItemPurchaseParams.inventoryItemPurchaseType)
+                inventoryItemPurchaseTypeInstance = InventoryItemPurchaseType.findByName(inventoryItemPurchaseParams.inventoryItemPurchaseType)
+                if(!inventoryItemPurchaseTypeInstance) {
+                    log.error "Inventory item purchase type not found on line: " + lineNumber
+                    log.debug inventoryItemPurchaseParams.inventoryItemPurchaseType
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+                inventoryItemPurchaseParams.inventoryItemPurchaseType = inventoryItemPurchaseTypeInstance
+
+                // CostCode.
+                if(inventoryItemPurchaseParams.costCode != '') {
+                    inventoryItemPurchaseParams.costCode = WordUtils.capitalizeFully(inventoryItemPurchaseParams.costCode)
+                    costCodeInstance = CostCode.findByName(inventoryItemPurchaseParams.costCode)
+                    if(!costCodeInstance) {
+                        costCodeInstance = new CostCode(name: inventoryItemPurchaseParams.costCode)
+                        if(!costCodeInstance.save()) {
+                            log.error "Failed to create cost code on line: " + lineNumber
+                            return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                        }
+                    }
+                    inventoryItemPurchaseParams.costCode = costCodeInstance
+                }
+
+                // Entered By.
+                inventoryItemPurchaseParams.enteredBy = inventoryItemPurchaseParams.enteredBy.toLowerCase()
+                personInstance = Person.findByLoginName(inventoryItemPurchaseParams.enteredBy)
+                if(!personInstance) {
+                    log.error "Entered by person not found on line: " + lineNumber
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+                inventoryItemPurchaseParams.enteredBy = personInstance
+
+                // Date Entered.
+                inventoryItemPurchaseParams.dateEntered = parseInputDate(inventoryItemPurchaseParams.dateEntered)
+
+                // Debug
+                log.debug "InventoryItemPurchaseParams: "
+                log.debug inventoryItemPurchaseParams
+
+                // Save inventoryItem.
+                log.info "Creating new purchase."
+                inventoryItemPurchaseInstance = new InventoryItemPurchase(inventoryItemPurchaseParams)
+
+                if(inventoryItemPurchaseInstance.hasErrors() || !inventoryItemPurchaseInstance.save()) {
+                    log.error "Failed to create item on line: " + lineNumber
+                    log.debug inventoryItemPurchaseInstance.errors
+                    return fail(code: "inventoryItemPurchase.import.failure", args: [lineNumber, logFileLink])
+                }
+
+                if(lineNumber % 100 == 0)
+                    cleanUpGorm()
+
+                if(!result.error) nextLine()
+            } //while(line)
+
+            // Success.
+            log.info "End of file."
+            reader.close()
+            return result
+
+
+         } //end withTransaction
+    } // end importInventoryItemPurchases()
+
+    private getTemplateHeaderLine1() {
+            ["Name*", "Description", "Comment", "Units In Stock", "Reorder Point*", "Reorder Quantity", "Unit Of Measure*",
+            "Estimated Unit Price", "Currency", "Enable Reorder", "Location*", "Store*", "Site*", "Group*", "Type*",
+            "Supplier's Part Number", "Preferred Supplier", "Alternate Suppliers",
+            "Spare For"]
+    }
+
+    private getPurchasesTemplateHeaderLine1() {
+            ["Inventory Item*", "Purchase Order Number*", "Quantity*", "Purchase Type*", "Cost Code*", "Entered By*",
+            "Date Entered*", "Order Value", "Currency", "Invoice Number"]
+    }
+
+    /**
+    * This cleans up the hibernate session and a grails map.
+    * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
+    * The hibernate session flush is normal for hibernate.
+    * The map is apparently used by grails for domain object validation errors.
+    * A starting point for clean up is every 100 objects.
+    */
+    def cleanUpGorm() {
+        def session = sessionFactory.currentSession
+        session.flush()
+        session.clear()
+        propertyInstanceMap.get().clear()
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/InventoryItemSearchService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/InventoryItemSearchService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/InventoryItemSearchService.groovy	(revision 875)
@@ -0,0 +1,368 @@
+import net.kromhouts.HqlBuilder
+import grails.orm.PagedResultList
+import org.compass.core.engine.SearchEngineQueryParseException
+
+/**
+* Service class that encapsulates the business logic for InventoryItem searches.
+*/
+class InventoryItemSearchService {
+
+    boolean transactional = false
+
+    def dateUtilService
+    def messageSource
+
+    def paramsMax = 100000
+
+    /**
+    * Selects and returns the correct search results based on the supplied quickSearch.
+    * @param params The request params, may contain params.quickSearch string to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getQuickSearch(params, locale) {
+        def result = [:]
+        result.quickSearch = params.quickSearch ?: "all"
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        switch (result.quickSearch) {
+            case "inventoryBelowReorder":
+                result.inventoryItemList = getInventoryBelowReorder(params)
+                if(result.inventoryItemList.totalCount > 0)
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.description")
+                else
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found")
+                break
+            case "inventoryBelowReorderAll":
+                result.inventoryItemList = getInventoryBelowReorder(params, false)
+                if(result.inventoryItemList.totalCount > 0)
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.all.description")
+                else
+                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found")
+                break
+            case "recentlyUsed":
+                result.daysBack = params.daysBack?.isInteger() ? params.daysBack.toInteger() : 14
+                result.inventoryItemList = getRecentlyUsed(params, result.daysBack)
+                if(result.inventoryItemList.totalCount > 0)
+                    result.message = getMessage(code:"inventoryItem.search.text.recently.used.description", args:[result.daysBack])
+                else
+                    result.message = getMessage(code:"inventoryItem.search.text.recently.used.none.found", args:[result.daysBack])
+                break
+            default:
+                result.inventoryItemList = getAll(params)
+                if(result.inventoryItemList.totalCount > 0)
+                    result.message = getMessage(code:"inventoryItem.search.text.all.description")
+                else
+                    result.message = getMessage(code:"inventoryItem.search.text.all.none.found")
+                break
+        } // switch.
+
+        // Success.
+        return result
+
+    } // getQuickSearch
+
+    /**
+    * Get all inventory items.
+    * @param params The request params.
+    */
+    def getAll(params) {
+        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        params.offset = params?.offset?.toInteger() ?: 0
+        params.sort = params?.sort ?: "name"
+        params.order = params?.order ?: "asc"
+
+        def inventoryItemList = InventoryItem.createCriteria().list(
+            max: params.max,
+            offset: params.offset,
+            sort: params.sort,
+            order: params.order) {
+            } // createCriteria
+    } // getAll
+
+    /**
+    * List inventory items that are below reorder point.
+    * @param params The request params.
+    * @param onlyReorderEnabled Only include items with reorder enabled, defaults to true.
+    */
+    def getInventoryBelowReorder(params, onlyReorderEnabled=true) {
+        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        params.offset = params?.offset?.toInteger() ?: 0
+        params.sort = params?.sort ?: "name"
+        params.order = params?.order ?: "asc"
+
+        def inventoryItemList = InventoryItem.createCriteria().list(
+            max: params.max,
+            offset: params.offset,
+            sort: params.sort,
+            order: params.order) {
+                eq("isActive", true)
+                if(onlyReorderEnabled)
+                    eq("enableReorderListing", true)
+                leProperty("unitsInStock", "reorderPoint")
+            } // createCriteria
+    } // getInventoryBelowReorder
+
+    /**
+    * Search for inventory items that are below reorder point.
+    * @param params The request params.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getReorderSearch(params, locale) {
+        def result = [:]
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        params.offset = params?.offset?.toInteger() ?: 0
+
+        def sort = "inventoryItem." + (params?.sort ?: "name")
+        def order = params?.order == "desc" ? "desc" : "asc"
+
+        def q = new HqlBuilder(max: params.max, offset: params.offset).query {
+            select 'count(distinct inventoryItem) as inventoryItemCount'
+            from 'InventoryItem as inventoryItem',
+                    'left join inventoryItem.alternateSuppliers as alternateSupplier'
+            where 'inventoryItem.unitsInStock <= inventoryItem.reorderPoint'
+                    and 'inventoryItem.isActive = true'
+                    and 'inventoryItem.isObsolete = false'
+
+                    if(!params.includeReorderListingDisabled)
+                        and "inventoryItem.enableReorderListing = true"
+
+                    if(params.selectedSupplier?.isLong()) {
+                        namedParams.supplier = Supplier.get(params.selectedSupplier.toLong())
+                        if(params.includeAlternateSuppliers)
+                            and "(inventoryItem.preferredSupplier = :supplier or alternateSupplier = :supplier)"
+                        else
+                            and "inventoryItem.preferredSupplier = :supplier"
+                    } // if selectedSupplier
+
+                    if(params.selectedGroups) {
+                        namedParams.selectedGroupIds = params.selectedGroups
+                        and  "inventoryItem.inventoryGroup.id in(:selectedGroupIds)"
+                    }
+
+                    if(!params.includeOnBackOrder) {
+                        // Subquery!
+                        def onBackOrder = new HqlBuilder().query {
+                            from "InventoryItemPurchase p"
+                            where "p.inventoryItem = inventoryItem"
+                                    and "p.inventoryItem = inventoryItem"
+                                    and "p.inventoryItemPurchaseType.id = 1" // Order Placed.
+                                    and "p.receivedComplete = false"
+                                    and "p.date > :oneMonthAgo"
+                        }
+
+                        namedParams.oneMonthAgo = new Date() - 30
+                        and "not exists ($onBackOrder.query)"
+                    }
+
+        } // query
+
+        def totalCount = InventoryItem.executeQuery(q.query, q.namedParams)[0].toInteger()
+
+        q.select = 'distinct inventoryItem'
+        q.order = "by $sort $order, inventoryItem.id asc"
+        def list = InventoryItem.executeQuery(q.query, q.namedParams, q.paginateParams)
+
+        result.inventoryItemList = new PagedResultList(list, totalCount)
+
+        // Get the result message.
+        if(result.inventoryItemList.totalCount > 0)
+            result.message = getMessage(code:"inventoryItem.search.text.below.reorder.description")
+        else
+            result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found")
+
+        // Success.
+        return result
+
+    } // getReorderSearch
+
+    /**
+    * Get a list of recently used inventory items.
+    * @param params The request params.
+    * @param daysBack The number of days back to get results for.
+    */
+    def getRecentlyUsed(params, daysBack) {
+        def paginateParams = [:]
+        paginateParams.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        paginateParams.offset = params?.offset?.toInteger() ?: 0
+
+        def sort = "inventoryItem." + (params?.sort ?: "name")
+        def order = params?.order == "desc" ? "desc" : "asc"
+        def orderBy = " order by " + sort + ' ' + order
+
+        def namedParams = [:]
+        namedParams.startOfDay = dateUtilService.today - daysBack
+
+        def baseQuery = "from InventoryItem as inventoryItem \
+                                        left join inventoryItem.inventoryMovements as inventoryMovement \
+                                        where (inventoryItem.isActive = true \
+                                                    and inventoryMovement.date > :startOfDay \
+                                                    and inventoryMovement.inventoryMovementType = 1 \
+                                                    )"
+
+        def searchQuery = "select distinct inventoryItem " + baseQuery + orderBy
+        def list = InventoryItem.executeQuery(searchQuery, namedParams, paginateParams)
+
+        def countQuery = "select count(distinct inventoryItem) as inventoryItemCount " + baseQuery
+        def totalCount = InventoryItem.executeQuery(countQuery, namedParams)[0].toInteger()
+
+        def inventoryItemInstanceList = new PagedResultList(list, totalCount)
+        return inventoryItemInstanceList
+    } // getRecentlyUsed
+
+    /**
+    * Get a list of inventory items by search text.
+    * @param params The request params.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getTextSearch(params, locale) {
+        def result = [:]
+        result.searchText = params.searchText.trim() ?: "" // User supplied text.
+        result.queryString = "" // Modified string that will be passed to searchable query.
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        params.offset = params?.offset?.toInteger() ?: 0
+        params.sort = params?.sort ?: "id"
+        params.order = params?.order ?: "asc"
+
+        // Build searchableParams.
+        // Do not include params.sort, since not all properites are indexed.
+        def searchableParams = [:]
+        searchableParams.max = params.max
+        searchableParams.offset = params.offset
+        searchableParams.reload = true
+        searchableParams.defaultOperator =  'or'
+        def properitesList = []
+        if(params.searchName)
+            properitesList << '$/InventoryItem/name'
+        if(params.searchDescription)
+            properitesList << '$/InventoryItem/description'
+        if(params.searchComment)
+            properitesList << '$/InventoryItem/comment'
+        if(params.searchLocation)
+            properitesList << '$/InventoryItem/inventoryLocation/name'
+        if(params.searchGroup)
+            properitesList << '$/InventoryItem/inventoryGroup/name'
+        if(params.searchSpareFor) {
+            properitesList << '$/InventoryItem/spareFor/name'
+            properitesList << '$/InventoryItem/spareFor/description'
+            properitesList << '$/InventoryItem/spareFor/comment'
+        }
+        if(properitesList)
+            searchableParams.properties = properitesList
+
+        // Check searchText for key words and modifiers.
+        def hasIsActive = result.searchText.contains('isActive')
+        def hasIsObsolete = result.searchText.contains('isObsolete')
+        def hasBracket = result.searchText.contains('(') || result.searchText.contains(')')
+        def containsModifier = { s ->
+            s.contains('"') ||
+            s.contains('~') ||
+            s.contains('*') ||
+            s.contains('(') ||
+            s.contains(')') ||
+            s.contains('+') ||
+            s.contains('-') ||
+            s.contains('^') ||
+            s.contains('OR') ||
+            s.contains('AND') ||
+            s.contains('NOT') ||
+            s.contains('TO') ||
+            s.contains('isObsolete') ||
+            s.contains('isActive')
+        }
+
+        // Expand search with wildcards.
+        def addWildcards = { text ->
+            text = text.tokenize().collect { token ->
+                if(!containsModifier(token))
+                    '*'+token+'*'
+                else
+                    token
+            }.join(' ')
+            return text
+        }
+
+        // Default isActive and isObsolete.
+        def addDefaultFlags = { text ->
+            if(!hasBracket)
+                text = '( '+text+' )'
+            if(!hasIsActive)
+                text = text + ' AND isActive:"true" '
+            if(!hasIsObsolete)
+                text = text + ' AND isObsolete:"false" '
+            return text
+        }
+
+        result.queryString = addWildcards(result.searchText)
+        result.queryString = addDefaultFlags(result.queryString)
+
+        // Perform the searchable query.
+        try {
+            result.inventoryItemList = InventoryItem.search(result.queryString, searchableParams)
+
+            // Would be nice if this worked.
+//             result.inventoryItemList = InventoryItem.search(result.searchText, searchableParams) {
+//                 must(term("isActive", true))
+//                 must(term("isObsolete", false))
+//             }
+
+        } catch (e) {
+            log.error e
+            result.inventoryItemList = [:]
+            result.inventoryItemList.results = []
+            result.inventoryItemList.total = 0
+        }
+
+        // Sort the returned instances.
+        if(params.sort != 'id') {
+            if(params.order == 'asc') {
+                if(params.sort == 'name' || params.sort == 'description')
+                    result.inventoryItemList.results.sort { p1, p2 -> p1[params.sort].compareToIgnoreCase(p2[params.sort]) }
+                else if(params.sort == 'inventoryGroup') {
+                    result.inventoryItemList.results.sort { p1, p2 ->
+                        p1.inventoryGroup.name.compareToIgnoreCase(p2.inventoryGroup.name)
+                    }
+                }
+                else if(params.sort == 'unitsInStock')
+                    result.inventoryItemList.results.sort {p1, p2 -> p1[params.sort]  <=> p2[params.sort] }
+            } // asc.
+            else {
+                if(params.sort == 'name' || params.sort == 'description')
+                    result.inventoryItemList.results.sort { p1, p2 -> p2[params.sort].compareToIgnoreCase(p1[params.sort]) }
+                else if(params.sort == 'inventoryGroup') {
+                    result.inventoryItemList.results.sort { p1, p2 ->
+                        p2.inventoryGroup.name.compareToIgnoreCase(p1.inventoryGroup.name)
+                    }
+                }
+                else if(params.sort == 'unitsInStock')
+                    result.inventoryItemList.results.sort {p1, p2 -> p2[params.sort] <=> p1[params.sort]}
+            } // desc.
+        } // sort.
+
+        // Create a PagedResultList.
+        result.inventoryItemList = new PagedResultList(result.inventoryItemList.results, result.inventoryItemList.total)
+
+        // Get the result message.
+        if(result.inventoryItemList.totalCount > 0)
+            result.message = getMessage(code:"inventoryItem.search.text.found", args: [result.queryString])
+        else
+            result.message = getMessage(code:"inventoryItem.search.text.none.found", args: [result.queryString])
+
+        // Success.
+        return result
+
+    } // getTextSearch()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/InventoryItemService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/InventoryItemService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/InventoryItemService.groovy	(revision 875)
@@ -0,0 +1,482 @@
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import org.apache.commons.lang.WordUtils
+
+/**
+* Provides a service class for the InventoryItem domain class.
+*/
+class InventoryItemService {
+
+    boolean transactional = false
+
+    def createDataService
+
+    def sessionFactory
+    def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
+
+    /**
+    * Prepare the data for the show view.
+    * The result can be used to easily construct the model for the show view.
+    * @param params The incoming params as normally passed to the show view
+    * primarily including the id of the inventoryItem.
+    * @returns A map containing result.error, if any error, otherwise result.inventoryItemInstance.
+    */
+    def show(params) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
+            return result
+        }
+
+        result.inventoryItemInstance = InventoryItem.get( params.id )
+
+        if(!result.inventoryItemInstance)
+            return fail(code:"default.not.found")
+
+        def p = [:]
+
+        if(params.paginate == "purchases") {
+            params.showTab = "showPurchasingTab"
+            p.max = Math.min(params.max?.toInteger() ?: 10, 100)
+            p.offset = params.offset?.toInteger() ?: 0
+            p.sort = params.sort ?: null
+            p.order = params.order ?: null
+        }
+        else {
+            p.max = 10
+            p.offset = 0
+        }
+
+        result.inventoryItemPurchasesTotal = InventoryItemPurchase.countByInventoryItem(result.inventoryItemInstance)
+
+        result.inventoryItemPurchases = InventoryItemPurchase.withCriteria {
+                eq("inventoryItem", result.inventoryItemInstance)
+                maxResults(p.max)
+                firstResult(p.offset)
+                // Sorting:
+                // Default is to sort by order number then id.
+                // When a sortable column is clicked then we sort by that.
+                // If the sortable column clicked is order number then we add id as the second sort.
+                if(p.sort && p.order) {
+                    order(p.sort, p.order)
+                    if(p.sort == "purchaseOrderNumber") order('id', 'asc')
+                }
+                else {
+                    order('purchaseOrderNumber', 'desc')
+                    order('id', 'asc')
+                }
+            }
+
+        result.showTab = [:]
+        switch (params.showTab) {
+            case "showMovementTab":
+                result.showTab.movement =  new String("true")
+                break
+            case "showPurchasingTab":
+                result.showTab.purchasing =  new String("true")
+                break
+            default:
+                result.showTab.inventory = new String("true")
+        }
+
+        p.max = result.inventoryMovementListMax = 10
+        p.offset = 0
+        p.order = "desc"
+        p.sort = "id"
+        result.inventoryMovementList = InventoryMovement.findAllByInventoryItem(result.inventoryItemInstance, p)
+        result.inventoryMovementListTotal = InventoryMovement.countByInventoryItem(result.inventoryItemInstance)
+
+
+        // Success.
+        return result
+
+    } // end show()
+
+    def delete(params) {
+        InventoryItem.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemInstance && m.field)
+                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
+                return result
+            }
+
+            result.inventoryItemInstance = InventoryItem.get(params.id)
+
+            if(!result.inventoryItemInstance)
+                return fail(code:"default.not.found")
+
+            if(result.inventoryItemInstance.inventoryMovements)
+                return fail(code:"inventoryMovement.still.associated")
+
+            try {
+                result.inventoryItemInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } //end withTransaction
+    } // end delete()
+
+    def edit(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
+            return result
+        }
+
+        result.inventoryItemInstance = InventoryItem.get(params.id)
+
+        if(!result.inventoryItemInstance)
+            return fail(code:"default.not.found")
+
+        // Success.
+        return result
+    }
+
+    def update(params) {
+        InventoryItem.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemInstance && m.field)
+                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
+                return result
+            }
+
+            result.inventoryItemInstance = InventoryItem.get(params.id)
+
+            if(!result.inventoryItemInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.inventoryItemInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            result.inventoryItemInstance.properties = params
+            result.inventoryItemInstance.setAlternateSuppliersFromCheckBoxList(params.alternateSuppliers)
+            result.inventoryItemInstance.setSpareForFromCheckBoxList(params.spareFor)
+
+            // Fetch to prevent lazy initialization error.
+            result.inventoryItemInstance.unitOfMeasure
+
+            if(result.inventoryItemInstance.hasErrors() || !result.inventoryItemInstance.save())
+                return fail(code:"default.update.failure")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end update()
+
+    def create(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
+            return result
+        }
+
+        result.inventoryItemInstance = new InventoryItem()
+        result.inventoryItemInstance.properties = params
+
+        // success
+        return result
+    }
+
+    def save(params) {
+        InventoryItem.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemInstance && m.field)
+                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
+                return result
+            }
+
+            result.inventoryItemInstance = new InventoryItem(params)
+            result.inventoryItemInstance.setAlternateSuppliersFromCheckBoxList(params.alternateSuppliers)
+            result.inventoryItemInstance.setSpareForFromCheckBoxList(params.spareFor)
+
+            if(result.inventoryItemInstance.hasErrors() || !result.inventoryItemInstance.save())
+                return fail(code:"default.create.failure")
+
+            // success
+            return result
+
+        } //end withTransaction
+    }
+
+    /**
+    * Save an inventory item picture.
+    * @param params An object or map containing at least the inventoryItem ID.
+    * @param pictureSource A supported source to get the picture image from.
+    * Supported sources:
+    * HttpServletRequest e.g: 'request' var from controller to run getFile('file') against.
+    * ServletContextResource e.g: grailsApplication.mainContext.getResource('images/logo.png')
+    * File e.g: new File('picture.jpg')
+    */
+    def savePicture(params, pictureSource) {
+        InventoryItem.withTransaction { status ->
+            def result = [:]
+
+            def kByteMultiplier = 1000
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemInstance && m.field)
+                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: m.args ?: ["InventoryItem", params.id] ]
+                return result
+            }
+
+            result.inventoryItemInstance = InventoryItem.get(params.id)
+
+            if(!result.inventoryItemInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.inventoryItemInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            if(result.inventoryItemInstance.picture)
+                return fail(field:"picture", code:"inventory.item.already.has.picture")
+
+            // Declare some more variables, since we appear to have most of what we need.
+            def picture = new Picture(inventoryItem: result.inventoryItemInstance)
+            def imaging = new Imaging()
+            def images = null
+            def pictureFile
+            def pictureFileName = ''
+            def pictureInputStream
+
+            // Check the supplied pictureSource and get the inputStream.
+            if(pictureSource instanceof javax.servlet.http.HttpServletRequest) {
+                def multiPartFile = pictureSource.getFile('file')
+                pictureFileName = multiPartFile.originalFilename
+
+                if(!multiPartFile || multiPartFile.isEmpty())
+                    return fail(code: "default.file.not.supplied")
+
+                if (multiPartFile.getSize() > Image.MAX_SIZE)
+                    return fail(code: "default.file.over.max.size", args: [Image.MAX_SIZE/kByteMultiplier, "kB"])
+
+                pictureInputStream = multiPartFile.inputStream
+            }
+            else if(pictureSource instanceof org.springframework.web.context.support.ServletContextResource) {
+                pictureFile = pictureSource.getFile()
+                pictureFileName = pictureFile.name
+
+                if ( !pictureFile.isFile() || (pictureFile.length() == 0) )
+                    return fail(code:"default.file.not.supplied")
+
+                if (pictureFile.length() > Image.MAX_SIZE)
+                    return fail(code:"default.file.over.max.size", args: [Image.MAX_SIZE/kByteMultiplier, "kB"])
+
+                pictureInputStream = pictureSource.inputStream
+            }
+            else if(pictureSource instanceof File) {
+                pictureFile = pictureSource
+                pictureFileName = pictureFile.name
+
+                if ( !pictureFile.isFile() || (pictureFile.length() == 0) )
+                    return fail(code:"default.file.not.supplied")
+
+                if (pictureFile.length() > Image.MAX_SIZE)
+                    return fail(code:"default.file.over.max.size", args: [Image.MAX_SIZE/kByteMultiplier, "kB"])
+
+                pictureInputStream = new FileInputStream(pictureSource)
+            }
+            else {
+                    return fail(code:"inventory.item.picture.source.not.supported")
+            }
+
+            // Create the Images.
+            try {
+                images = imaging.createAll(result.inventoryItemInstance, picture, pictureInputStream)
+                // Ensure the stream is closed.
+                pictureInputStream.close()
+            }
+            catch(Exception ex) {
+                log.error("picture save", ex)
+                // Ensure the stream is closed.
+                pictureInputStream.close()
+                return fail(code:"inventory.item.picture.file.unrecognised", args: [pictureFileName])
+            }
+
+            // Add images to picture.
+            images.each { image ->
+                picture.addToImages(image)
+            }
+
+            // Save picture.
+            if(picture.hasErrors() || !picture.save())
+                return fail(code:"default.create.failure", args: ["Picture"])
+
+            result.inventoryItemInstance.picture = picture
+
+            // Save inventoryItem.
+            if(result.inventoryItemInstance.hasErrors() || !result.inventoryItemInstance.save())
+                return fail(code:"default.create.failure")
+
+            // success
+            return result
+
+        } // end withTransaction
+    } // savePicture
+
+    /**
+    * Import inventory pictures from an uploaded zip file or picture.
+    * @param request The http request to run getFile against.
+    * Get file should return a zip format file containing the inventory item pictures or a picture file.
+    */
+    def importInventoryItemPictures(request) {
+            def result = [:]
+
+            def kByteMultiplier = 1000
+            def mByteMultiplier = 1000 * kByteMultiplier
+            def fileMaxSize = 100 * mByteMultiplier
+
+            def fail = { Map m ->
+                result.error = [ code: m.code, args: m.args ]
+                return result
+            }
+
+            // Get file from request.
+            def multiPartFile = request.getFile('file')
+            def uploadedFileName = multiPartFile.originalFilename
+
+            if(!multiPartFile || multiPartFile.isEmpty())
+                return fail(code: "default.file.not.supplied")
+
+            if (multiPartFile.getSize() > fileMaxSize)
+                return fail(code: "default.file.over.max.size", args: [fileMaxSize/mByteMultiplier, "MB"])
+
+            // Check and create import dir.
+            def dir = new File(ConfigurationHolder.config.globalDirs.tempInventoryItemPicturesDirectory)
+
+            if(!dir.exists())
+                dir.mkdirs()
+
+            if(!dir.isDirectory()) {
+                return fail(code:'inventoryItemPictures.import.failure.no.directory')
+            }
+
+            // Write file to disk.
+            def diskFile = new File(dir.absolutePath + File.separator + uploadedFileName)
+            multiPartFile.transferTo(diskFile)
+
+            // File patterns
+            def zipFilePattern = ~/[^\s].*(\.(?i)(zip))$/
+            def pictureFilePattern = ~/[^\s].*(\.(?i)(jpg|png|gif|bmp))$/
+
+            // If file claims to be a zip file then try using ant to unzip.
+            if(diskFile.name.matches(zipFilePattern)) {
+                def ant = new AntBuilder()
+                try {
+                    ant.unzip(  src: diskFile.absolutePath,
+                                        dest: dir.absolutePath,
+                                        overwrite:"true" )
+                }
+                catch(e) {
+                    log.error e
+                    return fail(code:'inventoryItemPictures.import.failure.to.unzip')
+                }
+            }
+
+            // Recurse through dir building list of pictureFiles.
+            def pictureFiles = []
+            dir.eachFileMatch(pictureFilePattern) {
+                pictureFiles << it
+            }
+
+            dir.eachDirRecurse { subDir ->
+                subDir.eachFileMatch(pictureFilePattern) {
+                    pictureFiles << it
+                }
+            }
+
+            pictureFiles.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+
+            // Find inventoryItems by name of picture and call savePicture.
+            def inventoryItemInstance
+            def itemName
+            def savePictureResult
+            def pictureCount = 0
+            def picturesSavedCount = 0
+
+            // Turn off index mirroring.
+            createDataService.stopSearchableIndex()
+
+            for(pictureFile in pictureFiles) {
+                pictureCount++
+
+                if(pictureCount % 10 == 0) {
+                    cleanUpGorm()
+                }
+
+                itemName = WordUtils.capitalize(pictureFile.name[0..-5])
+                inventoryItemInstance = InventoryItem.findByName(itemName)
+                if(!inventoryItemInstance) {
+                    log.warn 'InventoryItem not found with name: ' + itemName
+                    continue
+                }
+                if(inventoryItemInstance.picture) {
+                    log.warn 'InventoryItem already has picture: ' + itemName
+                    continue
+                }
+                savePictureResult = savePicture(inventoryItemInstance, pictureFile)
+                if(savePictureResult.error)
+                    log.error savePictureResult.error
+                else {
+                    picturesSavedCount++
+                    log.info 'InventoryItem picture saved: ' + itemName
+                }
+            }
+
+            // Start mirroring again and rebuild index.
+            createDataService.startSearchableIndex()
+
+            log.info 'InventoryItem pictures saved: ' + picturesSavedCount
+            log.info 'InventoryItem pictures total: ' + pictureCount
+
+            // Cleanup.
+            dir.eachFile() {
+                if(it.isDirectory())
+                    it.deleteDir()
+                else
+                    it.delete()
+            }
+
+            // Success.
+            return result
+
+    } // importInventoryItemPictures
+
+    /**
+    * This cleans up the hibernate session and a grails map.
+    * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
+    * The hibernate session flush is normal for hibernate.
+    * The map is apparently used by grails for domain object validation errors.
+    * A starting point for clean up is every 100 objects.
+    */
+    def cleanUpGorm() {
+        def session = sessionFactory.currentSession
+        session.flush()
+        session.clear()
+        propertyInstanceMap.get().clear()
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/InventoryMovementService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/InventoryMovementService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/InventoryMovementService.groovy	(revision 875)
@@ -0,0 +1,145 @@
+class InventoryMovementService {
+
+    boolean transactional = false
+
+    def authService
+    def authenticateService
+
+    def reverseMove(params) {
+        InventoryMovement.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryMovementInstance && m.field)
+                    result.inventoryMovementInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryMovement", params.id] ]
+                return result
+            }
+
+            result.inventoryMovementInstance = InventoryMovement.lock(params.id)
+
+             if(!result.inventoryMovementInstance)
+                fail(code:"default.not.found")
+
+            // Fetch to prevent lazy initialization error.
+            result.inventoryMovementInstance.inventoryItem.unitOfMeasure
+
+            // Used type must have a task that is not complete or in the trash
+            if(result.inventoryMovementInstance.inventoryMovementType.id == 1)  {
+
+                // Unlike move, if the task does not exist at all then deletion is still allowed.
+                if(result.inventoryMovementInstance.task?.trash)
+                    return fail(field:"task", code:"task.operationNotPermittedOnTaskInTrash")
+
+                if(result.inventoryMovementInstance.task?.taskStatus?.id == 3)
+                    return fail(field:"task", code:"task.operationNotPermittedOnCompleteTask")
+
+                // Check for authorisation on recurring tasks.
+                if(result.inventoryMovementInstance.task?.taskRecurringSchedule) {
+                    if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager,ROLE_InventoryManager'))
+                        return fail(field:"task", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+                }
+
+            }
+
+            result.inventoryItemInstance = InventoryItem.lock(result.inventoryMovementInstance.inventoryItem.id)
+            result.taskId = result.inventoryMovementInstance.task?.id
+
+            if(!result.inventoryItemInstance)
+                return fail(field:"inventoryItem", code:"inventoryMovement.inventoryItem.notFound")
+
+            // Reverse the movement of inventory.
+            if(!result.inventoryMovementInstance.inventoryMovementType.incrementsInventory) {
+                result.inventoryItemInstance.unitsInStock += result.inventoryMovementInstance.quantity
+            }
+            else {
+                if(result.inventoryItemInstance.unitsInStock >= result.inventoryMovementInstance.quantity) {
+                    result.inventoryItemInstance.unitsInStock -= result.inventoryMovementInstance.quantity
+                }
+                else {
+                    return fail(field:"quantity", code:"inventoryMovement.quantity.insufficientItemsInStock")
+                }
+            }
+
+            if(!result.inventoryItemInstance.save())
+                return fail(code: "default.delete.failure")
+
+            // Success..
+            result.inventoryMovementInstance.delete()
+            return result
+
+        } // end withTransaction
+    } //end reverseMove()
+
+    def move(params) {
+        InventoryMovement.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryMovementInstance && m.field)
+                    result.inventoryMovementInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryMovement", params.id] ]
+                return result
+            }
+
+            result.inventoryMovementInstance = new InventoryMovement(params)
+
+            result.inventoryMovementInstance.person = authService.currentUser
+
+            // Fetch to prevent lazy initialization error.
+            result.inventoryMovementInstance.inventoryItem.unitOfMeasure
+
+            // Used type must have a task that is not complete or in the trash
+            if(result.inventoryMovementInstance.inventoryMovementType.id == 1)  {
+
+                if(!result.inventoryMovementInstance.task)
+                    return fail(field:"task", code:"task.notFound")
+
+                if(result.inventoryMovementInstance.task.trash)
+                    return fail(field:"task", code:"task.operationNotPermittedOnTaskInTrash")
+
+                if(result.inventoryMovementInstance.task.taskStatus.id == 3)
+                    return fail(field:"task", code:"task.operationNotPermittedOnCompleteTask")
+
+                // Check for authorisation on recurring tasks.
+                if(result.inventoryMovementInstance.task.taskRecurringSchedule) {
+                    if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager,ROLE_InventoryManager'))
+                        return fail(field:"task", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+                }
+            }
+
+            // Bail early if validation fails.
+            if(!result.inventoryMovementInstance.validate())
+                return fail(code:"default.create.failure")
+
+            def inventoryItem = InventoryItem.lock(result.inventoryMovementInstance.inventoryItem.id)
+            result.taskId = result.inventoryMovementInstance.task?.id
+
+            if(!inventoryItem)
+                return fail(field:"inventoryItem", code:"inventoryMovement.inventoryItem.notFound")
+
+            // Perform the movement of inventory.
+            if(result.inventoryMovementInstance.inventoryMovementType.incrementsInventory) {
+                inventoryItem.unitsInStock += result.inventoryMovementInstance.quantity
+            }
+            else {
+                if(inventoryItem.unitsInStock >= result.inventoryMovementInstance.quantity) {
+                    inventoryItem.unitsInStock -= result.inventoryMovementInstance.quantity
+                }
+                else {
+                    return fail(field:"quantity", code:"inventoryMovement.quantity.insufficientItemsInStock")
+                }
+            }
+
+            if(!inventoryItem.save() || !result.inventoryMovementInstance.save())
+                return fail(code:"default.create.failure")
+
+            // Success..
+            return result
+
+        } // end withTransaction
+    } // end move()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/InventoryPurchaseService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/InventoryPurchaseService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/InventoryPurchaseService.groovy	(revision 875)
@@ -0,0 +1,478 @@
+class InventoryPurchaseService {
+
+    boolean transactional = false
+
+    def authService
+    def dateUtilService
+    def inventoryMovementService
+
+    /**
+    * Calulates the quantities for an inventoryItem and purchaseOrderNumber.
+    * @param order An inventory purchase that was the source of the order.
+    * @returns A result map containing the totalOrdered, totalReceived, totalRemaining, thisOrderRemaining,
+    *                 totalOrderedAmount, totalReceivedAmount, totalRemainingAmount, thisOrderRemainingAmount,
+    *                 totalPaymentApproved.
+    */
+    def calcQuantities(order) {
+
+        def result = [:]
+
+        result.totalOrdered = 0
+        result.totalOrderedAmount = 0
+        result.totalReceived = 0
+        result.totalReceivedAmount = 0
+        result.totalPaymentApproved = 0
+        InventoryItemPurchase.withCriteria {
+            eq("inventoryItem", order.inventoryItem)
+            eq("purchaseOrderNumber", order.purchaseOrderNumber)
+        }.each() {
+            if(it.inventoryItemPurchaseType.id == 1L) { // Orders.
+                result.totalOrdered += it.quantity
+                result.totalOrderedAmount += it.orderValueAmount
+            }
+            if(it.inventoryItemPurchaseType.id == 2L || it.inventoryItemPurchaseType.id == 3L) { // Received B/order and Complete.
+                result.totalReceived += it.quantity
+                result.totalReceivedAmount += it.orderValueAmount
+            }
+            if(it.inventoryItemPurchaseType.id == 4L) { // Approved.
+                result.totalPaymentApproved += it.orderValueAmount
+            }
+        }
+
+        result.totalRemaining
+        if(result.totalOrdered > result.totalReceived)
+            result.totalRemaining = result.totalOrdered - result.totalReceived
+        else
+            result.totalRemaining = 0
+
+        result.totalRemainingAmount
+        if(result.totalOrderedAmount > result.totalReceivedAmount)
+            result.totalRemainingAmount = result.totalOrderedAmount - result.totalReceivedAmount
+        else
+            result.totalRemainingAmount = 0
+
+        result.thisOrderRemaining
+        if(result.totalRemaining > order.quantity)
+            result.thisOrderRemaining = order.quantity
+        else
+            result.thisOrderRemaining = result.totalRemaining
+
+        result.thisOrderRemainingAmount
+        if(result.totalRemainingAmount > order.orderValueAmount)
+            result.thisOrderRemainingAmount = order.orderValueAmount
+        else
+            result.thisOrderRemainingAmount = result.totalRemainingAmount
+
+        return result
+    }
+
+    /**
+    * Get the original order for an inventoryItemPurchase and InventoryItem.
+    * @param inventoryItemPurchase An inventory puchase.
+    * @returns The order.
+    */
+    def getOriginalOrder(inventoryItemPurchase) {
+
+        def namedParams = [:]
+
+        namedParams.inventoryItem = inventoryItemPurchase.inventoryItem
+        namedParams.purchaseOrderNumber = inventoryItemPurchase.purchaseOrderNumber
+        namedParams.orderPlaced = InventoryItemPurchaseType.read(1)
+
+        def order = InventoryItemPurchase.find("from InventoryItemPurchase as p \
+                                                                                where( p.inventoryItem = :inventoryItem \
+                                                                                            and p.purchaseOrderNumber = :purchaseOrderNumber \
+                                                                                            and p.inventoryItemPurchaseType = :orderPlaced )",
+                                                                            namedParams)
+
+        return order
+    }
+
+    /**
+    * Get costCodes by person and the purchasingGroups they have been assigned.
+    * @param person A Person, defaults to currentUser.
+    * @returns A list of CostCodes.
+    */
+    def getCostCodesByPerson(person = authService.currentUser) {
+        if(person.purchasingGroups) {
+            CostCode.withCriteria {
+                    eq('isActive', true)
+                    or {
+                        person.purchasingGroups.each() { purchasingGroup ->
+                            eq('purchasingGroup', purchasingGroup)
+                        }
+                    }
+            }.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } // withCriteria
+        }
+        else
+            []
+    } // getCostCodesByPerson
+
+    /**
+    * Check if a person is in a purchasing group.
+    * @param person A PurchasingGroup to check for.
+    * @param person A Person, defaults to currentUser.
+    * @returns True if person is in group.
+    */
+    def isPersonInPurchasingGroup(purchasingGroup, person = authService.currentUser) {
+        for(pg in person.purchasingGroups) {
+            if(pg.id == purchasingGroup.id)
+                return true
+        }
+    } // isPersonInPurchasingGroup
+
+    def delete(params) {
+        InventoryItemPurchase.withTransaction { status ->
+            def result = [:]
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemPurchase && m.field)
+                    result.inventoryItemPurchase.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItemPurchase", params.id] ]
+                return result
+            }
+
+            result.inventoryItemPurchaseInstance = InventoryItemPurchase.get(params.id)
+
+            if(!result.inventoryItemPurchaseInstance)
+                return fail(code:"default.not.found")
+
+            result.inventoryItemId = result.inventoryItemPurchaseInstance.inventoryItem.id
+            def purchaseTypeId = result.inventoryItemPurchaseInstance.inventoryItemPurchaseType.id
+
+            // Handle Invoice Payment Approved.
+            if(purchaseTypeId == 4) {
+                // Find and mark all orders as invoicePaymentApproved = false.
+                InventoryItemPurchase.withCriteria {
+                    eq("inventoryItem", result.inventoryItemPurchaseInstance.inventoryItem)
+                    eq("purchaseOrderNumber", result.inventoryItemPurchaseInstance.purchaseOrderNumber)
+                    inventoryItemPurchaseType {
+                            eq("id", 1L) // Order Placed.
+                    }
+                }.each() {
+                    it.invoicePaymentApproved = false
+                }
+                // Find and mark last orderReceived as invoicePaymentApproved = false.
+                InventoryItemPurchase.withCriteria {
+                    eq("inventoryItem", result.inventoryItemPurchaseInstance.inventoryItem)
+                    eq("purchaseOrderNumber", result.inventoryItemPurchaseInstance.purchaseOrderNumber)
+                    inventoryItemPurchaseType {
+                        or {
+                            eq("id", 2L) // Received B/order To Come
+                            eq("id", 3L) // Received Complete
+                        }
+                    }
+                }.last().invoicePaymentApproved = false
+            }
+
+            // Handle Received.
+            // Refuse to delete if payment approved.
+            // Find and reverse the matching movement.
+            // Find and mark all orders as receivedComplete = false.
+            if(purchaseTypeId == 2 || purchaseTypeId == 3) {
+
+                def paymentAlreadyApproved = InventoryItemPurchase.withCriteria {
+                    eq("inventoryItem", result.inventoryItemPurchaseInstance.inventoryItem)
+                    eq("purchaseOrderNumber", result.inventoryItemPurchaseInstance.purchaseOrderNumber)
+                    inventoryItemPurchaseType {
+                            eq("id", 4L) // Invoice Payment Approved.
+                    }
+                }
+
+                if(paymentAlreadyApproved)
+                    return fail(code:"inventoryItemPurchase.delete.failure.payment.approved")
+
+                def startOfDay = dateUtilService.getMidnight(result.inventoryItemPurchaseInstance.date)
+                def inventoryMovements = InventoryMovement.withCriteria {
+                    eq("inventoryItem", result.inventoryItemPurchaseInstance.inventoryItem )
+                    eq("quantity", result.inventoryItemPurchaseInstance.quantity)
+                    between("date", startOfDay, startOfDay+1)
+                    inventoryMovementType {
+                        eq("id", 3L) // purchaseReceived.
+                    }
+                    order('id', 'desc') // The newest one will be first.
+                }
+
+                def movementResult = inventoryMovementService.reverseMove(inventoryMovements[0])
+                if(movementResult.error)
+                    return fail(code:"inventoryMovement.quantity.insufficientItemsInStock")
+
+                InventoryItemPurchase.withCriteria {
+                    eq("inventoryItem", result.inventoryItemPurchaseInstance.inventoryItem)
+                    eq("purchaseOrderNumber", result.inventoryItemPurchaseInstance.purchaseOrderNumber)
+                    inventoryItemPurchaseType {
+                            eq("id", 1L) // Order Placed
+                    }
+                }.each() {
+                    it.receivedComplete = false
+                }
+            } // Handle Received.
+
+            // Handle Order Placed.
+            // Refuse to delete if we have received items.
+            // Deletion of received already requires payment approved to be deleted.
+            if(purchaseTypeId == 1) {
+                def calcQuantities = calcQuantities(result.inventoryItemPurchaseInstance)
+                if(calcQuantities.totalReceived > 0)
+                    return fail(code:"inventoryItemPurchase.delete.failure.received.exists")
+            }
+
+            // Success.
+            // By this stage everything should be handled and the delete call is allowed and expected to pass.
+            result.inventoryItemPurchaseInstance.delete()
+            return result
+
+        } // end withTransaction
+    }
+
+    def edit(params) {
+        def result = [:]
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: ["InventoryItemPurchase", params.id] ]
+            return result
+        }
+
+        result.inventoryItemPurchaseInstance = InventoryItemPurchase.get(params.id)
+
+        if(!result.inventoryItemPurchaseInstance)
+            return fail(code:"default.not.found")
+
+        // Success.
+        return result
+    }
+
+    def update(params) {
+        InventoryItemPurchase.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemPurchaseInstance && m.field)
+                    result.inventoryItemPurchaseInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItemPurchase", params.id] ]
+                return result
+            }
+
+            result.inventoryItemPurchaseInstance = InventoryItemPurchase.get(params.id)
+
+            if(!result.inventoryItemPurchaseInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.inventoryItemPurchaseInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            def originalPaymentApprovedAmount = result.inventoryItemPurchaseInstance.orderValueAmount
+
+            result.inventoryItemPurchaseInstance.properties = params
+            result.inventoryItemPurchaseInstance.purchaseOrderNumber = result.inventoryItemPurchaseInstance.purchaseOrderNumber.trim()
+            result.inventoryItemPurchaseInstance.invoiceNumber = result.inventoryItemPurchaseInstance.invoiceNumber.trim()
+            result.inventoryItemPurchaseInstance.lastUpdatedBy = authService.currentUser
+
+            // Fetch to prevent lazy initialization error.
+            result.inventoryItemPurchaseInstance.inventoryItem.unitOfMeasure
+
+            //  If processing an Invoice Approved.
+            if(result.inventoryItemPurchaseInstance.inventoryItemPurchaseType.id == 4L) {
+                if(!result.inventoryItemPurchaseInstance.invoiceNumber)
+                    return fail(field:"invoiceNumber", code:"inventoryItemPurchase.invoiceNumber.required")
+            }
+
+            if(result.inventoryItemPurchaseInstance.hasErrors() || !result.inventoryItemPurchaseInstance.save())
+                return fail(code:"default.update.failure")
+
+            //  If processing an Invoice Approved.
+            if(result.inventoryItemPurchaseInstance.inventoryItemPurchaseType.id == 4L) {
+
+                def order = getOriginalOrder(result.inventoryItemPurchaseInstance)
+                if(!order)
+                    return fail(code:"default.not.found")
+
+                // Update orderValueAmount if receivedComplete.
+                if(order.receivedComplete) {
+
+                    def calcQuantities = calcQuantities(order)
+                    order.orderValueAmount = calcQuantities.totalPaymentApproved
+
+                    if(order.hasErrors() || !order.save())
+                        return fail(code:"default.create.failure")
+                }
+
+            }
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end update()
+
+    def save(params) {
+        InventoryItemPurchase.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemPurchase && m.field)
+                    result.inventoryItemPurchase.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItemPurchase", params.id] ]
+                return result
+            }
+
+            result.inventoryItemPurchaseInstance = new InventoryItemPurchase(params)
+            result.inventoryItemPurchaseInstance.purchaseOrderNumber = result.inventoryItemPurchaseInstance.purchaseOrderNumber.trim()
+            result.inventoryItemPurchaseInstance.enteredBy = authService.currentUser
+            result.inventoryItemPurchaseInstance.inventoryItemPurchaseType = InventoryItemPurchaseType.read(1) // Order
+
+            // Fetch to prevent lazy initialization error.
+            result.inventoryItemPurchaseInstance.inventoryItem.unitOfMeasure
+
+            // Prevent ordering on obsolete or inactive inventoryItem.
+            def isObsolete = result.inventoryItemPurchaseInstance.inventoryItem?.isObsolete
+            def isActive = result.inventoryItemPurchaseInstance.inventoryItem?.isActive
+            if(isObsolete || !isActive)
+                return fail(code:"inventoryItemPurchase.operation.not.permitted.on.inactive.or.obsolete.item")
+
+            if(result.inventoryItemPurchaseInstance.hasErrors() || !result.inventoryItemPurchaseInstance.save())
+                return fail(code:"default.create.failure")
+
+            result.inventoryItemId = result.inventoryItemPurchaseInstance.inventoryItem.id
+
+            // success
+            return result
+
+        } // end withTransaction
+    } // save()
+
+    def receiveSave(params) {
+        InventoryItemPurchase.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemPurchase && m.field)
+                    result.inventoryItemPurchase.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItemPurchase", params.id] ]
+                return result
+            }
+
+            def order = InventoryItemPurchase.get(params.orderId)
+            if(!order)
+                return fail(code:"default.not.found")
+            result.orderId = order.id
+
+            result.inventoryItemPurchaseInstance = new InventoryItemPurchase(params)
+            result.inventoryItemPurchaseInstance.enteredBy = authService.currentUser
+            result.inventoryItemPurchaseInstance.purchaseOrderNumber = order.purchaseOrderNumber
+            result.inventoryItemPurchaseInstance.costCode = order.costCode
+            result.inventoryItemPurchaseInstance.orderValueCurrency = order.orderValueCurrency
+
+            def calcQuantities = calcQuantities(order)
+            if(result.inventoryItemPurchaseInstance.quantity)
+                calcQuantities.totalReceived += result.inventoryItemPurchaseInstance.quantity
+            if(result.inventoryItemPurchaseInstance.orderValueAmount)
+                calcQuantities.totalReceivedAmount += result.inventoryItemPurchaseInstance.orderValueAmount
+
+            if(calcQuantities.totalReceived >= calcQuantities.totalOrdered) {
+                order.receivedComplete = true
+                result.inventoryItemPurchaseInstance.receivedComplete = true
+                result.inventoryItemPurchaseInstance.inventoryItemPurchaseType = InventoryItemPurchaseType.read(3) // Received Complete.
+            }
+            else {
+                order.receivedComplete = false
+                result.inventoryItemPurchaseInstance.inventoryItemPurchaseType = InventoryItemPurchaseType.read(2) // Received B/oder to Come.
+            }
+
+            // Fetch to prevent lazy initialization error.
+            result.inventoryItemPurchaseInstance.inventoryItem.unitOfMeasure
+            result.inventoryItemPurchaseInstance.inventoryItem.inventoryLocation
+
+            if(order.hasErrors() || !order.save())
+                return fail(code:"default.create.failure")
+
+            if(result.inventoryItemPurchaseInstance.hasErrors() || !result.inventoryItemPurchaseInstance.save())
+                return fail(code:"default.create.failure")
+
+            result.inventoryItemId = result.inventoryItemPurchaseInstance.inventoryItem.id
+
+            // Perform the inventory movement.
+            if(result.inventoryItemPurchaseInstance.quantity > 0) {
+                def p = [:]
+                p.inventoryItem = result.inventoryItemPurchaseInstance.inventoryItem
+                p.quantity = result.inventoryItemPurchaseInstance.quantity
+                p.inventoryMovementType = InventoryMovementType.read(3)
+                def movementResult = inventoryMovementService.move(p)
+                if(movementResult.error)
+                    return fail(code:"default.create.failure")
+            }
+
+            // success
+            return result
+
+        } // end withTransaction
+    } // receiveSave()
+
+    def approveInvoicePaymentSave(params) {
+        InventoryItemPurchase.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemPurchaseInstance && m.field)
+                    result.inventoryItemPurchaseInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItemPurchase", params.id] ]
+                return result
+            }
+
+            def received = InventoryItemPurchase.get(params.receivedId)
+            if(!received)
+                return fail(code:"default.not.found")
+            result.receivedId = received.id
+
+            def order = getOriginalOrder(received)
+            if(!order)
+                return fail(code:"default.not.found")
+            result.orderId = order.id
+
+            result.inventoryItemPurchaseInstance = new InventoryItemPurchase(params)
+            result.inventoryItemPurchaseInstance.enteredBy = authService.currentUser
+            result.inventoryItemPurchaseInstance.purchaseOrderNumber = order.purchaseOrderNumber
+            result.inventoryItemPurchaseInstance.costCode = order.costCode
+            result.inventoryItemPurchaseInstance.orderValueCurrency = order.orderValueCurrency
+            result.inventoryItemPurchaseInstance.inventoryItemPurchaseType = InventoryItemPurchaseType.read(4) // Approve.
+
+            received.invoicePaymentApproved = true
+            result.inventoryItemPurchaseInstance.invoicePaymentApproved = true
+
+            // Update orderValueAmount and invoicePaymentApproved if processing a receivedComplete.
+            if(received.inventoryItemPurchaseType.id == 3L) {
+                order.invoicePaymentApproved = true
+                result.inventoryItemPurchaseInstance.receivedComplete = true
+                def calcQuantities = calcQuantities(order)
+                if(result.inventoryItemPurchaseInstance.orderValueAmount)
+                    calcQuantities.totalPaymentApproved += result.inventoryItemPurchaseInstance.orderValueAmount
+                order.orderValueAmount = calcQuantities.totalPaymentApproved
+            }
+
+            // Fetch to prevent lazy initialization error.
+            result.inventoryItemPurchaseInstance.inventoryItem.unitOfMeasure
+
+            if(!result.inventoryItemPurchaseInstance.invoiceNumber)
+                return fail(field:"invoiceNumber", code:"inventoryItemPurchase.invoiceNumber.required")
+
+            if(order.hasErrors() || !order.save())
+                return fail(code:"default.create.failure")
+
+            if(result.inventoryItemPurchaseInstance.hasErrors() || !result.inventoryItemPurchaseInstance.save())
+                return fail(code:"default.create.failure")
+
+            result.inventoryItemId = result.inventoryItemPurchaseInstance.inventoryItem.id
+
+            // Success..
+            return result
+
+        } // end withTransaction
+    } // approveInvoicePaymentSave()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/InventoryReportService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/InventoryReportService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/InventoryReportService.groovy	(revision 875)
@@ -0,0 +1,365 @@
+
+import net.kromhouts.HqlBuilder
+
+/**
+* Service class that encapsulates the business logic for Inventory Reports.
+*/
+class InventoryReportService {
+
+    boolean transactional = false
+
+//     def authService
+//     def dateUtilService
+//     def messageSource
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    // Protect java heap memory.
+    // Most likely want to set paramsMax and inClauseMax to the same values.
+    def paramsMax = 250
+
+    // At least with Oracle and MSSQL db limits are 1000 (in list) and 2000 (nodes) respectively.
+    // But 255 has also been mentioned on the internet as a possible limit for some databases.
+    def inClauseMax = 250
+
+    /**
+    * Get the data for the inventory stock take overiew report.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getStockTakeOverview(params, locale) {
+        def result = [:]
+
+        result.summaryOfCalculationMethod = 'This report should be used in conjunction with the `Stock Take (By Location)` Report.'
+
+        def namedParams = [:]
+
+        result.query = "from InventoryLocation as inventoryLocation \
+                                        left join inventoryLocation.inventoryStore as inventoryStore \
+                                        where (inventoryLocation.isActive = true \
+                                                    ) \
+                                        order by inventoryStore.name, inventoryLocation.name"
+
+        result.query = "select new Map(inventoryLocation.name as location, inventoryStore.name as store) " + result.query
+        result.queryResult = InventoryLocation.executeQuery(result.query, namedParams)
+        result.inventoryLocationCount = result.queryResult.size()
+
+        result.inventoryLocationList = result.queryResult
+
+        // Success.
+        return result
+
+    } // getStockTakeOverview()
+
+    /**
+    * Get the data for the inventory stock take by location report.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getStockTakeByLocation(params, locale) {
+        def result = [:]
+
+        result.inventoryItemList = []
+        result.inventoryItemCount = 0
+        result.locationCount = 0
+        result.errorMessage = null
+        result.summaryOfCalculationMethod = 'This report should be used in conjunction with the `Stock Take (Overview)` Report.'
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: m.args ]
+            result.errorMessage = g.message(result.error)
+            result.locations = ''
+            return result
+        }
+
+        def paginateParams = [:]
+        paginateParams.max = Math.min(params?.max?.toInteger() ?: paramsMax, paramsMax)
+
+        def namedParams = [:]
+        namedParams.locationList = []
+
+        // Sanitise the user supplied locations string and convert to a list.
+        result.locations = params.locationString.trim()
+        if(result.locations.startsWith('e.g:'))
+            result.locations = result.locations.split(':')[-1].trim()
+        result.locations = result.locations.split(',')
+        result.locations = result.locations.collect {it.trim()}
+
+        // Fill namedParams.locationList.
+        result.locations.each() { location ->
+            if(namedParams.locationList.size() < paramsMax) {
+                // paramsMax+1 to ensure the too many locations check bellow is triggered.
+                namedParams.locationList += InventoryLocation.findAllByNameIlike(location, [max: paramsMax+1])
+            }
+            namedParams.locationList.unique()
+        }
+
+        // Return the actual locations as a string, along with a count.
+        result.locationCount = namedParams.locationList.size()
+        if(result.locationCount > 0) {
+            namedParams.locationList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+            result.locations = namedParams.locationList.toString()[1..-2]
+        }
+        else
+            result.locations = g.message(code: 'default.none.text')
+
+        // Exit if empty location list.
+        // Protects against HQL unexpected end of subtree exception with an empty list.
+        if(namedParams.locationList.isEmpty())
+            return fail(code:'report.error.no.locations.found')
+
+        // Exit if IN clause list too big.
+        if(namedParams.locationList.size() > inClauseMax)
+            return fail(code:'report.error.too.many.locations', args: [inClauseMax])
+
+        // Inventory List.
+        result.inventoryListQuery = "from InventoryItem as inventoryItem \
+                                                        left join inventoryItem.inventoryLocation as inventoryLocation \
+                                                        where (inventoryItem.isActive = true \
+                                                                    and  inventoryItem.inventoryLocation in (:locationList) \
+                                                                    ) "
+
+        result.inventoryCountQuery = "select count(distinct inventoryItem) " + result.inventoryListQuery
+        result.inventoryItemCount = InventoryItem.executeQuery(result.inventoryCountQuery, namedParams)[0]
+
+        // Exit if too many results.
+        if(result.inventoryItemCount > paramsMax) 
+            return fail(code:'report.error.too.many.results', args: [paramsMax])
+
+        result.inventoryListQuery = "select distinct inventoryItem " + result.inventoryListQuery
+        def inventoryList = InventoryItem.executeQuery(result.inventoryListQuery, namedParams, paginateParams)
+
+        // Reset namedParams for next query.
+        namedParams = [:]
+        namedParams.inventoryList = inventoryList
+
+        // Exit if empty inventory list.
+        // Protects against HQL unexpected end of subtree exception with an empty list.
+        if(namedParams.inventoryList.isEmpty())
+            return fail(code:'report.error.no.inventory.items.found')
+
+        // Exit if inventory list too big.
+        if(namedParams.inventoryList.size() > inClauseMax)
+            return fail(code:'report.error.too.many.inventory.items', args: [inClauseMax])
+
+        // Note: HQL docs advise 'not using fetch aliases in where clause (or any other clause)'.
+        // Access is via the parent object, however that does not work for the order by clause in this case.
+        result.query = "from InventoryItem as inventoryItem \
+                                        left join fetch inventoryItem.unitOfMeasure as unitOfMeasure \
+                                        left join fetch inventoryItem.inventoryLocation as inventoryLocation \
+                                        left join fetch inventoryLocation.inventoryStore as inventoryStore \
+                                        left join fetch inventoryItem.picture as picture \
+                                        left join fetch picture.images as Image \
+                                        where (inventoryItem in (:inventoryList) \
+                                                    ) \
+                                        order by inventoryStore.name, inventoryLocation.name"
+
+        // MSSQL will not do distinct here, for some reason it tries to compare the image data type!
+        result.query = "select inventoryItem " + result.query
+        result.inventoryItemList = InventoryItem.executeQuery(result.query, namedParams, paginateParams)
+
+        result.inventoryItemList.unique()
+
+        // Success.
+        return result
+
+    } // getStockTakeOverview()
+
+    /**
+    * Get the data for the inventory value with detail.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getInventoryValueDetailed(params, locale) {
+        def result = [:]
+
+        result.inventoryItemList = []
+        result.inventoryItemCount = 0
+        result.inventoryItemTotalValue = new BigDecimal(0)
+        result.currency = null
+        result.errorMessage = null
+        result.summaryOfCalculationMethod = "This report does not convert between different currency.\n"
+        result.summaryOfCalculationMethod += "Therefore all item's are checked to ensure that currency is the same."
+
+        result.site = Site.get(params.site.id.toLong())
+
+        result.inventoryTypes = []
+        if(params.inventoryTypes instanceof String)
+            result.inventoryTypes << InventoryType.get(params.inventoryTypes.toInteger())
+        else if(params.inventoryTypes)
+            result.inventoryTypes = params.inventoryTypes.collect { InventoryType.get(it.toInteger()) }
+        else
+            result.inventoryTypes = InventoryType.findAllByIsActive(true, [max:254, sort:'name'])
+
+        result.inventoryGroups = []
+        if(params.inventoryGroups instanceof String)
+            result.inventoryGroups << InventoryGroup.get(params.inventoryGroups.toInteger())
+        else if(params.inventoryGroups)
+            result.inventoryGroups = params.inventoryGroups.collect { InventoryGroup.get(it.toInteger()) }
+        else
+            result.inventoryGroups = InventoryGroup.findAllByIsActive(true, [max:254, sort:'name'])
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: m.args ]
+            result.errorMessage = g.message(result.error)
+            result.currency = null
+            result.inventoryItemTotalValue = new BigDecimal(0)
+            return result
+        }
+
+        def q = new HqlBuilder().query {
+            select 'distinct inventoryItem'
+            from 'InventoryItem as inventoryItem',
+                    'left join fetch inventoryItem.inventoryLocation as inventoryLocation',
+                    'left join fetch inventoryLocation.inventoryStore as inventoryStore',
+                    'left join fetch inventoryItem.unitOfMeasure as unitOfMeasure'
+            where 'inventoryItem.isActive = true'
+                namedParams.siteId = result.site.id
+                and 'inventoryStore.site.id = :siteId'
+                if(result.inventoryTypes) {
+                    namedParams.inventoryTypeIds = result.inventoryTypes.collect {it.id}
+                    and 'inventoryItem.inventoryType.id in(:inventoryTypeIds)'
+                }
+                if(result.inventoryGroups) {
+                    namedParams.inventoryGroupIds = result.inventoryGroups.collect {it.id}
+                    and 'inventoryItem.inventoryGroup.id in(:inventoryGroupIds)'
+                }
+            order 'by inventoryItem.name asc'
+        }
+
+        result.inventoryItemList = InventoryItem.executeQuery(q.query, q.namedParams)
+        result.inventoryItemCount = result.inventoryItemList.size()
+        result.currency = result.inventoryItemList[0]?.estimatedUnitPriceCurrency
+
+        for(inventoryItem in result.inventoryItemList) {
+            // Check all currency is the same.
+            if(result.currency != inventoryItem.estimatedUnitPriceCurrency) {
+                fail(code:'report.error.multiple.currency.found') // No return, populate errors but continue report.
+                break
+            }
+            if(inventoryItem.estimatedUnitPriceAmount && inventoryItem.unitsInStock) // Some items have null estimatedUnitPriceAmount.
+                result.inventoryItemTotalValue += inventoryItem.estimatedUnitPriceAmount * inventoryItem.unitsInStock
+        } // for
+
+        /// @todo: This protects against a bug in the report layout, remove when solved.
+        if(result.inventoryTypes.size() > 4)
+            result.inventoryTypes = [[name:'More than 4']]
+
+        if(result.inventoryGroups.size() > 4)
+            result.inventoryGroups =  [[name:'More than 4']]
+
+        // Success.
+        return result
+
+    } // getInventoryValueDetailed()
+
+    /**
+    * Get the data for the inventory overiew value.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getInventoryValueOverview(params, locale) {
+        def result = [:]
+
+        result.inventoryItemCount = 0
+        result.inventoryItemTotalValue = new BigDecimal(0)
+        result.currency = null
+        result.errorMessage = null
+        result.summaryOfCalculationMethod = "This report does not convert between different currency.\n"
+        result.summaryOfCalculationMethod += "Therefore all item's are checked to ensure that currency is the same."
+
+        result.site = Site.get(params.site.id.toLong())
+
+        result.inventoryTypes = []
+        if(params.inventoryTypes instanceof String)
+            result.inventoryTypes << InventoryType.get(params.inventoryTypes.toInteger())
+        else if(params.inventoryTypes)
+            result.inventoryTypes = params.inventoryTypes.collect { InventoryType.get(it.toInteger()) }
+        else
+            result.inventoryTypes = InventoryType.findAllByIsActive(true, [max:254, sort:'name'])
+
+        result.inventoryGroups = []
+        if(params.inventoryGroups instanceof String)
+            result.inventoryGroups << InventoryGroup.get(params.inventoryGroups.toInteger())
+        else if(params.inventoryGroups)
+            result.inventoryGroups = params.inventoryGroups.collect { InventoryGroup.get(it.toInteger()) }
+        else
+            result.inventoryGroups = InventoryGroup.findAllByIsActive(true, [max:254, sort:'name'])
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: m.args ]
+            result.errorMessage = g.message(result.error)
+            result.currency = null
+            //result.inventoryItemTotalValue = new BigDecimal(0)
+            return result
+        }
+
+        // Base query.
+        def q = new HqlBuilder().query {
+            select ''
+            from 'InventoryItem as inventoryItem',
+                    'left join inventoryItem.inventoryLocation as inventoryLocation',
+                    'left join inventoryLocation.inventoryStore as inventoryStore'
+            where 'inventoryItem.isActive = true'
+                namedParams.siteId = result.site.id
+                and 'inventoryStore.site.id = :siteId'
+                namedParams.groupIds = result.inventoryGroups.collect {it.id}
+                and 'inventoryItem.inventoryGroup.id in(:groupIds)'
+                namedParams.typeIds = result.inventoryTypes.collect {it.id}
+                and 'inventoryItem.inventoryType.id in(:typeIds)'
+        }
+        def baseWhereLogic = new ArrayList(q.whereClauseTerms)
+
+        // Count the inventoryItems.
+        q.select = 'count(distinct inventoryItem)'
+        result.inventoryItemCount = InventoryItem.executeQuery(q.query, q.namedParams)[0]
+
+        // Get the first currency found on this site.
+        q.paginateParams.max = 1
+        q.select = 'inventoryItem.estimatedUnitPriceCurrency'
+        result.currency = InventoryItem.executeQuery(q.query, q.namedParams, q.paginateParams)[0]
+
+        // Count the distinct currency found.
+        q.select = 'count(distinct inventoryItem.estimatedUnitPriceCurrency)'
+        def currencyCount = InventoryItem.executeQuery(q.query, q.namedParams)[0]
+
+        // Get total value.
+        q.select = 'sum (inventoryItem.estimatedUnitPriceAmount * inventoryItem.unitsInStock)'
+        result.inventoryItemTotalValue = InventoryItem.executeQuery(q.query, q.namedParams)[0]
+
+        // Get values for each group.
+        def tempGroups = []
+        result.inventoryGroups.each() { group ->
+            q.namedParams.groupIds = [group.id]
+            def groupValue = InventoryItem.executeQuery(q.query, q.namedParams)[0] ?: 0
+            tempGroups << [name: group.name, value: groupValue]
+        }
+        q.namedParams.groupIds = result.inventoryGroups.collect {it.id} // reset.
+        result.inventoryGroups = tempGroups
+
+        // Get values for each type.
+        def tempTypes = []
+        result.inventoryTypes.each() { type ->
+            q.namedParams.typeIds = [type.id]
+            def typeValue = InventoryItem.executeQuery(q.query, q.namedParams)[0] ?: 0
+            tempTypes << [name: type.name, value: typeValue]
+        }
+        result.inventoryTypes = tempTypes
+
+        /// @todo: This protects against a bug in the report layout, remove when solved.
+        if(result.inventoryTypes.size() > 4)
+            result.inventoryTypes = [[name:'More than 4', value: 0]]
+
+        if(result.inventoryGroups.size() > 4)
+            result.inventoryGroups =  [[name:'More than 4', value: 0]]
+
+        // Check all currency is the same.
+        if(currencyCount > 1)
+            fail(code:'report.error.multiple.currency.found') // No return, populate errors but continue report.
+
+        // Success.
+        return result
+
+    } // getInventoryValueOverview()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/JsUtilService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/JsUtilService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/JsUtilService.groovy	(revision 875)
@@ -0,0 +1,91 @@
+/**
+* Provides some javascript utility methods.
+* For use with JsUtilTagLib.
+*/
+class JsUtilService {
+
+    boolean transactional = false
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    /**
+    * Toggle the visibility of an html element.
+    * @param id The html id of the element.
+    * @param type The type of html action the javascript will be applied to e.g 'onclick', defaults to 'href'.
+    * @returns A javascript string that can be assigned for example to an anchor href or onclick action.
+    */
+    def toggle(id, type="href") {
+        def s = 'toggleUtil(\"' + id + '\");'
+        if(type == "onclick")
+            s + ' return false;'
+        else
+            'javascript: ' + s
+    }
+
+    /**
+    * Toggle the visibility of an html element and update an image.
+    * @param toggleId The html id of the element to toggle.
+    * @param imageid The html id of the image to update.
+    * @param openImgUrl The url to apply as the image src when toggled element is visible.
+    * @param closedImgUrl The url to apply as the image src when toggled element is hidden.
+    * @param type The type of html action the javascript will be applied to e.g 'onclick', defaults to 'href'.
+    * @returns A javascript string that can be assigned for example to an anchor href or onclick action.
+    */
+    def toggleWithImg(toggleId, imageid, openImgUrl, closedImgUrl, type="href") {
+
+        def s = 'toggleWithImgUtil(\"' + toggleId +'\", \"' + imageid +'\", \"' + openImgUrl +'\", \"' + closedImgUrl +'\");'
+        if(type == "onclick")
+            s + ' return false;'
+        else
+            'javascript: ' + s
+
+    }
+
+    /**
+    * Show an html element by slowly increasing the visibility.
+    * @param id The html id of the element.
+    * @param type The type of html action the javascript will be applied to e.g 'onclick', defaults to 'href'.
+    * @returns A javascript string that can be assigned for example to an anchor href or onclick action.
+    */
+    def show(id) {
+        def s = 'showUtil(\"' + id + '\");'
+        if(type == "onclick")
+            s + ' return false;'
+        else
+            'javascript: ' + s
+    }
+
+    /**
+    * Hide an html element by slowly decreasing the visibility.
+    * @param id The html id of the element.
+    * @param type The type of html action the javascript will be applied to e.g 'onclick', defaults to 'href'.
+    * @returns A javascript string that can be assigned for example to an anchor href or onclick action.
+    */
+    def hide(id) {
+        def s = 'hideUtil(\"' + id + '\");'
+        if(type == "onclick")
+            s + ' return false;'
+        else
+            'javascript: ' + s
+    }
+
+    /**
+    * Toggle the visibility of an html element and update an image.
+    * @param toggleId The html id of the element to toggle.
+    * @param imageid The html id of the image to update.
+    * @param openImgUrl The url to apply as the image src when toggled element is visible.
+    * @param closedImgUrl The url to apply as the image src when toggled element is hidden.
+    * @param type The type of html action the javascript will be applied to e.g 'onclick', defaults to 'href'.
+    * @returns A javascript string that can be assigned for example to an anchor href or onclick action.
+    */
+    def toggleWithImgAndEffect(toggleId, imageid, openImgUrl, closedImgUrl, type="href") {
+
+        def s = 'toggleWithImgAndEffectUtil(\"' + toggleId +'\", \"' + imageid +'\", \"' + openImgUrl +'\", \"' + closedImgUrl +'\");'
+        if(type == "onclick")
+            s + ' return false;'
+        else
+            'javascript: ' + s
+
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/PersonCsvService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/PersonCsvService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/PersonCsvService.groovy	(revision 875)
@@ -0,0 +1,257 @@
+import grails.util.GrailsUtil
+import au.com.bytecode.opencsv.CSVWriter
+import au.com.bytecode.opencsv.CSVReader
+import org.apache.commons.lang.WordUtils
+
+/**
+ * Provides some csv import/export methods.
+ * Requires the opencsv jar to be available which is included in the grails-export plugin.
+ */
+class PersonCsvService {
+
+    boolean transactional = false
+
+    def authService
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    def sessionFactory
+    def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP
+
+    /**
+    * Import persons creating items as required.
+    */
+    def importPersons(request) {
+        Person.withTransaction { status ->
+            def result = [:]
+
+            def kByteMultiplier = 1000
+            def fileMaxSize = 800 * kByteMultiplier
+            def logFileLink = g.link(controller: "appCore", action: "appLog") {"log"}
+
+            def multiPartFile = request.getFile('file')
+
+            InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
+            CSVReader reader = new CSVReader(sr)
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                reader.close()
+                result.error = [ code: m.code, args: m.args ]
+                return result
+            }
+
+            if(!multiPartFile || multiPartFile.isEmpty())
+                return fail(code: "default.file.not.supplied")
+
+            if (multiPartFile.getSize() > fileMaxSize)
+                return fail(code: "default.file.over.max.size", args: [fileMaxSize/kByteMultiplier, "kB"])
+
+            def line = []
+            def lineNumber = 0
+            def maxNumberOfColumns = 13
+            def personParams = [:]
+            def personProperties = ["loginName", "firstName", "lastName",
+                                                    "ROLE_Manager", "ROLE_AppUser",
+                                                    "ROLE_TaskManager", "ROLE_TaskUser",
+                                                    "ROLE_InventoryManager", "ROLE_InventoryUser",
+                                                    "ROLE_AssetManager", "ROLE_AssetUser",
+                                                    "ROLE_ProductionManager", "ROLE_ProductionUser"]
+
+            def personInstance
+            def loginNamesAndPasswords = [:]
+
+            def nextLine = {
+                    line = reader.readNext()
+                    lineNumber ++
+                    log.info "Processing line: " + lineNumber
+            }
+
+            // Get first line.
+            nextLine()
+
+            // Check for header line 1.
+            if(line != templateHeaderLine1) {
+                log.error "Failed to find header line 1. "
+                log.error "Required: " + templateHeaderLine1.toString()
+                log.error "Supplied: " + line.toString()
+                return fail(code: "default.file.no.header")
+            }
+
+            log.info "Header line found."
+
+            // Prepare the first body line.
+            nextLine()
+
+            // Primary loop.
+            while(line) {
+
+                if(line.size() > maxNumberOfColumns) {
+                    log.error "Too many columns on line: " + lineNumber
+                    return fail(code: "person.import.failure", args: [lineNumber, logFileLink])
+                }
+
+                // Ignore comment lines.
+                if(line.toString().toLowerCase().contains("comment")) {
+                    log.info "Comment line found."
+                    nextLine()
+                    continue
+                }
+
+                // Ignore example lines.
+                if(line.toString().toLowerCase().contains("example")) {
+                    log.info "Example line found."
+                    nextLine()
+                    continue
+                }
+
+                // Parse the line into the params map.
+                personParams = [:]
+                line.eachWithIndex { it, j ->
+                    personParams."${personProperties[j]}" = it.trim()
+                }
+
+                // Debug
+                log.debug " Supplied params: "
+                log.debug personParams
+
+                // Ignore blank lines.
+                if(personParams.loginName == '') {
+                    log.info "No login name found."
+                    nextLine()
+                    continue
+                }
+
+                // Login Name.
+                personParams.loginName = personParams.loginName.toLowerCase()
+
+                // First Name.
+                personParams.firstName = WordUtils.capitalizeFully(personParams.firstName)
+
+                // First Name.
+                personParams.lastName = WordUtils.capitalizeFully(personParams.lastName)
+
+                // Password.
+                personParams.pass = personParams.pass ?: authService.randomPassword
+
+                // Debug
+                log.debug "personParams: "
+                log.debug personParams
+
+                personInstance = Person.findByLoginName(personParams.loginName)
+
+                if(!personInstance) {
+                    log.info "Creating person with login name: " + personParams.loginName
+                    personInstance = new Person(loginName: personParams.loginName,
+                                                                                firstName: personParams.firstName,
+                                                                                lastName: personParams.lastName,
+                                                                                pass: personParams.pass,
+                                                                                password: authService.encodePassword(personParams.pass))
+
+                    // Save.
+                    if(personInstance.hasErrors() || !personInstance.save()) {
+                        log.error "Failed to create person on line: " + lineNumber
+                        log.debug personInstance.errors
+                        return fail(code: "person.import.failure", args: [lineNumber, logFileLink])
+                    }
+
+                    // Fill map with persons and passwords.
+                    loginNamesAndPasswords."${personParams.loginName}" = personParams.pass
+                }
+                else
+                    log.info "Person already exists with login name: " + personParams.loginName
+
+                // Add Authorities.
+                if('true'.equalsIgnoreCase(personParams.ROLE_Manager))
+                    personInstance.addToAuthorities(Authority.get(2))
+                if('true'.equalsIgnoreCase(personParams.ROLE_AppUser))
+                    personInstance.addToAuthorities(Authority.get(3))
+                if('true'.equalsIgnoreCase(personParams.ROLE_TaskManager))
+                    personInstance.addToAuthorities(Authority.get(4))
+                if('true'.equalsIgnoreCase(personParams.ROLE_TaskUser))
+                    personInstance.addToAuthorities(Authority.get(5))
+                if('true'.equalsIgnoreCase(personParams.ROLE_InventoryManager))
+                    personInstance.addToAuthorities(Authority.get(6))
+                if('true'.equalsIgnoreCase(personParams.ROLE_InventoryUser))
+                    personInstance.addToAuthorities(Authority.get(7))
+                if('true'.equalsIgnoreCase(personParams.ROLE_AssetManager))
+                    personInstance.addToAuthorities(Authority.get(8))
+                if('true'.equalsIgnoreCase(personParams.ROLE_AssetUser))
+                    personInstance.addToAuthorities(Authority.get(9))
+                if('true'.equalsIgnoreCase(personParams.ROLE_ProductionManager))
+                    personInstance.addToAuthorities(Authority.get(10))
+                if('true'.equalsIgnoreCase(personParams.ROLE_ProductionUser))
+                    personInstance.addToAuthorities(Authority.get(11))
+
+                if(lineNumber % 100 == 0)
+                    cleanUpGorm()
+
+                if(!result.error) nextLine()
+            } //while(line)
+
+            // Success.
+            log.info "End of file."
+            result.loginNamesAndPasswords = g.message(code: "person.import.success") + '\n'
+            result.loginNamesAndPasswords += "Login names and passwords: " + '\n'
+            result.loginNamesAndPasswords += '\n'
+            loginNamesAndPasswords.each() { result.loginNamesAndPasswords += (it.key + ' : ' + it.value + '\n') }
+            reader.close()
+            return result
+
+         } //end withTransaction
+    } // end importPersons()
+
+    /**
+    * Build a persons template csv file.
+    * This template can then be populated for import.
+    * @returns The template as a String in csv format.
+    */
+    def buildPersonsTemplate() {
+
+        StringWriter sw = new StringWriter()
+        CSVWriter writer = new CSVWriter(sw)
+
+        writeTemplateLines(writer)
+
+        writer.close()
+        return sw.toString()
+    }
+
+    private writeTemplateLines(writer) {
+        writer.writeNext(templateHeaderLine1 as String[])
+        writer.writeNext()
+        writer.writeNext("Comment: The header line is required.")
+        writer.writeNext("Comment: Required columns are marked with a (*) in the header line.")
+        writer.writeNext("Comment: Lists of items in a column must be separated by a semicolon (;), not a comma.")
+        writer.writeNext("Comment: Role columns must be 'true' or 'false'.")
+        writer.writeNext("Comment: Identical and existing names will be considered as the same item.")
+        writer.writeNext("Comment: Lines containing 'comment' will be ignored.")
+        writer.writeNext("Comment: Lines containing 'example' will be ignored.")
+        writer.writeNext("Comment: This file must be saved as a CSV file before import.")
+        writer.writeNext()
+    }
+
+    private getTemplateHeaderLine1() {
+            ["Login Name*", "First Name*", "Last Name*",
+            "Role: Business Manager*", "Role: Application User*",
+            "Role: Task Manager*", "Role: Task User*",
+            "Role: Inventory Manager*", "Role: Inventory User*",
+            "Role: Asset Manager*", "Role: Asset User*",
+            "Role: Production Manager*", "Role: Production User*"]
+    }
+
+    /**
+    * This cleans up the hibernate session and a grails map.
+    * For more info see: http://naleid.com/blog/2009/10/01/batch-import-performance-with-grails-and-mysql/
+    * The hibernate session flush is normal for hibernate.
+    * The map is apparently used by grails for domain object validation errors.
+    * A starting point for clean up is every 100 objects.
+    */
+    def cleanUpGorm() {
+        def session = sessionFactory.currentSession
+        session.flush()
+        session.clear()
+        propertyInstanceMap.get().clear()
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/SectionService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/SectionService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/SectionService.groovy	(revision 875)
@@ -0,0 +1,55 @@
+class SectionService {
+
+    boolean transactional = false
+
+    def assetSubItemService
+    def assetService
+
+    def delete(params) {
+        Section.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.sectionInstance && m.field)
+                    result.sectionInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Section", params.id] ]
+                return result
+            }
+
+            result.sectionInstance = Section.get(params.id)
+
+            if(!result.sectionInstance)
+                return fail(code:"default.not.found")
+
+            if(result.sectionInstance.maintenanceActions)
+                return fail(code:"maintenanceActions.still.associated")
+
+            // Delete assets which in turn delete orphan assetSubItems.
+            def assets = new ArrayList(result.sectionInstance.assets) // avoid ConcurrentModificationException.
+            def r
+            for(asset in assets) {
+                result.sectionInstance.removeFromAssets(asset)
+                r = assetService.delete(id: asset.id)
+                if(r.error) {
+                    log.debug r.error
+                    fail(code:"section.asset.delete.failure")
+                    break
+                }
+            }
+
+            if(result.error)
+                return result
+
+            try {
+                result.sectionInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } // end withTransaction
+    } // end delete()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/SiteService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/SiteService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/SiteService.groovy	(revision 875)
@@ -0,0 +1,54 @@
+class SiteService {
+
+    boolean transactional = false
+
+    def sectionService
+
+    def delete(params) {
+        Site.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.siteInstance && m.field)
+                    result.siteInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Site", params.id] ]
+                return result
+            }
+
+            result.siteInstance = Site.get(params.id)
+
+            if(!result.siteInstance)
+                return fail(code:"default.not.found")
+
+            if(result.siteInstance.inventoryStores)
+                return fail(code:"inventoryStores.still.associated")
+
+            // Delete sections which in turn deletes assets etc.
+            def sections = new ArrayList(result.siteInstance.sections) // avoid ConcurrentModificationException.
+            def r
+            for(section in sections) {
+                result.siteInstance.removeFromSections(section)
+                r = sectionService.delete(id: section.id)
+                if(r.error) {
+                    log.debug r.error
+                    fail(code:"site.section.delete.failure")
+                    break
+                }
+            }
+
+            if(result.error)
+                return result
+
+            try {
+                result.siteInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } // end withTransaction
+    } // end delete()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/TaskProcedureService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/TaskProcedureService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/TaskProcedureService.groovy	(revision 875)
@@ -0,0 +1,212 @@
+/**
+* Provides a service class for the TaskProcedure domain class.
+*/
+class TaskProcedureService {
+
+    boolean transactional = false
+
+    def authService
+    def dateUtilService
+
+    /**
+    * Updates an existing taskProcedure.
+    * @param params The params to update for taskProcedure with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskProcedureInstance (if available).
+    */
+    def update(params) {
+        TaskProcedure.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskProcedureInstance && m.field)
+                    result.taskProcedureInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["TaskProcedure", params.id] ]
+                // Fetch to prevent lazy initialization error.
+                result.taskProcedureInstance.revisions.each {it.createdBy.toString()}
+                return result
+            }
+
+            result.taskProcedureInstance = TaskProcedure.get(params.id)
+
+            if(!result.taskProcedureInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskProcedureInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            result.taskProcedureInstance.properties = params
+
+            // Gaps in the html index's can be created by adding 2 items and removing the first one.
+            // This creates a gap at the missing index where LazyList will return a null.
+            def nullMaintenanceActions = result.taskProcedureInstance.maintenanceActions.findAll {!it}
+            if (nullMaintenanceActions) {
+                result.taskProcedureInstance.maintenanceActions.removeAll(nullMaintenanceActions)
+            }
+            def nullDocumentReferences = result.taskProcedureInstance.documentReferences.findAll {!it}
+            if (nullDocumentReferences) {
+                result.taskProcedureInstance.documentReferences.removeAll(nullDocumentReferences)
+            }
+
+            // Save for restoration if validation fails.
+            def savedMaintenanceActions = new ArrayList(result.taskProcedureInstance.maintenanceActions)
+            def savedDocumentReferences = new ArrayList(result.taskProcedureInstance.documentReferences)
+
+            // Remove toBeDeleted before validation.
+            def ma_toBeDeleted = result.taskProcedureInstance.maintenanceActions.findAll {it.toBeDeleted}
+            if (ma_toBeDeleted) {
+                result.taskProcedureInstance.maintenanceActions.removeAll(ma_toBeDeleted)
+            }
+            def docRef_toBeDeleted = result.taskProcedureInstance.documentReferences.findAll {it.toBeDeleted}
+            if (docRef_toBeDeleted) {
+                result.taskProcedureInstance.documentReferences.removeAll(docRef_toBeDeleted)
+            }
+
+            if(result.taskProcedureInstance.hasErrors() || !result.taskProcedureInstance.save()) {
+                // Restore the saved items, some of which contain toBeDeleted flags but
+                // have not been deleted yet since validation failed.
+                // The toBeDeleted items are hidden in the view.
+                result.taskProcedureInstance.maintenanceActions = savedMaintenanceActions
+                result.taskProcedureInstance.documentReferences = savedDocumentReferences
+                // Populate collection errors for display.
+                result.taskProcedureInstance.maintenanceActions.each { it.validate() }
+                result.taskProcedureInstance.documentReferences.each { it.validate() }
+                return fail(code:"default.update.failure")
+            }
+
+            // Sort MaintenanceActions.
+            result.taskProcedureInstance.maintenanceActions.sort { p1, p2 -> p1.procedureStepNumber <=> p2.procedureStepNumber }
+
+            def r = createRevision(result.taskProcedureInstance)
+            if(r.error)
+                return fail(field:'id', code:"default.create.revision.failure")
+
+            // Also sets: taskInstance.taskProcedureRevision = taskProcedureRevision
+            r.taskProcedureRevision.addToTasks(result.taskProcedureInstance.linkedTask)
+
+            // Update tasks that are using previousRevision.
+            // Only those that are not started and due to be started today or in the future.
+            def previousRevision = result.taskProcedureInstance.getRevision(r.taskProcedureRevision.revision - 1)
+            if(previousRevision) {
+                Task.withCriteria {
+                    eq("taskProcedureRevision", previousRevision)
+                    ge("targetStartDate", dateUtilService.today)
+                    taskStatus {
+                        idEq(1L) // Not Started.
+                    }
+                    maxResults(10000)
+                }.each {
+                    it.taskProcedureRevision = r.taskProcedureRevision
+                }
+            }
+
+            // Success.
+            return result
+
+        } // end withTransaction
+    }  // end update()
+
+    /**
+    * Creates a new taskProcedure with the given params.
+    * @param params The params to use when creating the new taskProcedure.
+    * @returns A map containing result.error (if any error) and result.taskProcedure.
+    */
+    def save(params) {
+        def result = [:]
+        TaskProcedure.withTransaction { status ->
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskProcedureInstance && m.field)
+                    result.taskProcedureInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["TaskProcedure", params.id] ]
+                // Fetch to prevent lazy initialization error.
+                result.taskProcedureInstance.linkedTask.primaryAsset
+                return result
+            }
+
+            result.taskProcedureInstance = new TaskProcedure(params)
+
+            // Optimistic locking check on linkedTask.
+            if(result.taskProcedureInstance.linkedTask.taskProcedureRevision)
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+
+            // Gaps in the html index's can be created by adding 2 items and removing the first one.
+            // This creates a gap at the missing index where LazyList will return a null.
+            def nullMaintenanceActions = result.taskProcedureInstance.maintenanceActions.findAll {!it}
+            if (nullMaintenanceActions) {
+                result.taskProcedureInstance.maintenanceActions.removeAll(nullMaintenanceActions)
+            }
+            def nullDocumentReferences = result.taskProcedureInstance.documentReferences.findAll {!it}
+            if (nullDocumentReferences) {
+                result.taskProcedureInstance.documentReferences.removeAll(nullDocumentReferences)
+            }
+
+            if(result.taskProcedureInstance.hasErrors() || !result.taskProcedureInstance.save()) {
+                // Populate collection errors for display.
+                result.taskProcedureInstance.maintenanceActions.each { it.validate() }
+                result.taskProcedureInstance.documentReferences.each { it.validate() }
+                return fail(code:"default.create.failure")
+            }
+
+            // Sort MaintenanceActions.
+            result.taskProcedureInstance.maintenanceActions.sort { p1, p2 -> p1.procedureStepNumber <=> p2.procedureStepNumber }
+
+            def r = createRevision(result.taskProcedureInstance)
+            if(r.error)
+                return fail(field:'id', code:"default.create.revision.failure")
+
+            // Also sets: taskInstance.taskProcedureRevision = taskProcedureRevision
+            r.taskProcedureRevision.addToTasks(result.taskProcedureInstance.linkedTask)
+
+        } // end withTransaction
+
+        // Success.
+        return result
+    }  // end save()
+
+    /**
+    * Creates a new taskProcedureRevision.
+    * @param taskProcedureInstance The taskProcedure to create the revision for.
+    * @returns A map containing result.error (if any error) and result.taskProcedureRevision.
+    */
+    def createRevision(taskProcedureInstance) {
+        def result = [:]
+        TaskProcedureRevision.withTransaction { status ->
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskProcedureRevision && m.field)
+                    result.taskProcedureRevision.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["TaskProcedureRevision"] ]
+                return result
+            }
+
+            result.taskProcedureRevision = new TaskProcedureRevision()
+            taskProcedureInstance.addToRevisions(result.taskProcedureRevision)
+
+            result.taskProcedureRevision.taskProcedure = taskProcedureInstance
+            result.taskProcedureRevision.linkedTask = taskProcedureInstance.linkedTask
+            result.taskProcedureRevision.createdBy =  authService.currentUser
+            result.taskProcedureRevision.revision = 0 // init to prevent DataIntegrityViolationException
+            result.taskProcedureRevision.revision = taskProcedureInstance.revision
+            taskProcedureInstance.maintenanceActions.each {
+                result.taskProcedureRevision.addToMaintenanceActions(new MaintenanceAction(it.properties))
+            }
+            taskProcedureInstance.documentReferences.each {
+                result.taskProcedureRevision.addToDocumentReferences(new DocumentReference(it.properties))
+            }
+
+            if(result.taskProcedureRevision.hasErrors() || !result.taskProcedureRevision.save()) {
+                log.error result.taskProcedureRevision.errors
+                return fail(code:"default.create.failure")
+            }
+
+        } // end withTransaction
+
+        // Success.
+        return result
+    } // end createRevision()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/TaskRecurringScheduleService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/TaskRecurringScheduleService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/TaskRecurringScheduleService.groovy	(revision 875)
@@ -0,0 +1,195 @@
+class TaskRecurringScheduleService {
+
+    boolean transactional = false
+
+    // Can hold state since the service is a singleton.
+    boolean baseDataWarnLogged = false
+
+    def taskService
+    def dateUtilService
+    def appConfigService
+
+    /**
+    * Generate all enabled recurring tasks.
+    */
+    def generateAll() {
+
+        // Prevent errors if base data has not yet been created.
+        if(!appConfigService.exists("baseDataCreated")) {
+            if(!baseDataWarnLogged) {
+                log.warn "Base data has not been created, can't generate all."
+                baseDataWarnLogged = true
+            }
+            return
+        }
+
+        def p = [:]
+        def targetCompletionDate
+        def nextTargetCompletionDate
+        def tomorrow = dateUtilService.tomorrow
+
+        def taskRecurringScheduleList = TaskRecurringSchedule.findAllByEnabled(true)
+
+        // Stop generation if max reached.
+        def maxSubTasksReached = {
+            if( (it.maxSubTasks > 0) && (it.subTasksGenerated >= it.maxSubTasks) ) {
+                it.enabled = false
+                return true
+            }
+            return false
+        }
+
+        // Stop generation by targetCompletionDate.
+        def targetCompletionDateReached = {
+            if( it.useTargetCompletionDate) {
+                targetCompletionDate = dateUtilService.getMidnight(it.task.targetCompletionDate)
+                nextTargetCompletionDate = dateUtilService.getMidnight(it.nextTargetCompletionDate)
+                if(nextTargetCompletionDate > targetCompletionDate) {
+                    it.enabled = false
+                    return true
+                }
+            }
+            return false
+        }
+
+        // Main loop.
+        for(it in taskRecurringScheduleList) {
+
+            if(maxSubTasksReached(it))
+                continue
+
+            if(targetCompletionDateReached(it))
+                continue
+
+            if (dateUtilService.tomorrow > it.nextGenerationDate) {
+                p = [:]
+
+                // Build the subTask params.
+                p.targetStartDate = it.nextTargetStartDate
+                p.targetCompletionDate = it.nextTargetCompletionDate
+                if(it.task.taskProcedureRevision) p.taskProcedureRevision = it.task.taskProcedureRevision
+                if(it.task.assignedGroups) p.assignedGroups = new ArrayList(it.task.assignedGroups)
+                if(it.task.assignedPersons) p.assignedPersons = new ArrayList(it.task.assignedPersons)
+
+                def result = taskService.createSubTask(it.task, p)
+                if( !result.error ) {
+                    it.lastGeneratedSubTask = result.taskInstance
+                    it.subTasksGenerated++
+                    it.setNextTargetStartDate()
+                    it.setNextGenerationDate()
+                    it.setNextTargetCompletionDate()
+                }
+                else {
+                    log.error "Sub task generation for recurring schedule ${it.id} failed."
+                    log.error result.taskInstance.errors
+                }
+            }
+
+            // Run the completion reached checks for a second time so
+            // that this recurring schedule does not run again if
+            // there are no more subTasks to be generated.
+            if(maxSubTasksReached(it))
+                continue
+
+            if(targetCompletionDateReached(it))
+                continue
+
+        } // for()
+    } // generateAll()
+
+    /**
+    * Creates a new recurring schedule for a task with the given params.
+    * @param params The params to use when creating the new recurring schedule.
+    * @returns A map containing result.error=true (if any error) and result.taskRecurringScheduleInstance and result.taskId.
+    */
+    def create(params) {
+        TaskRecurringSchedule.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Object[] args ->
+                status.setRollbackOnly()
+                if(args.size() == 2) result.taskRecurringScheduleInstance.errors.rejectValue(args[0], args[1])
+                result.error = true
+                return result
+            }
+
+            result.taskRecurringScheduleInstance = new TaskRecurringSchedule(params)
+            result.taskId = result.taskRecurringScheduleInstance.task.id
+
+            if(!result.taskRecurringScheduleInstance.validate())
+                return fail()
+
+            def taskInstance = Task.lock(result.taskId)
+
+            if(!taskInstance)
+                return fail('task', "task.notFound")
+
+            if(taskInstance.taskRecurringSchedule)
+                return fail('task', "tast.taskRecurringSchedule.alreadyExists")
+
+            if(taskInstance.taskStatus.id == 3)
+                return fail('task', "task.operationNotPermittedOnCompleteTask")
+
+            if(taskInstance.trash)
+                return fail('task', "task.operationNotPermittedOnTaskInTrash")
+
+            if(result.taskRecurringScheduleInstance.nextTargetStartDate < dateUtilService.today)
+                return fail("nextTargetStartDate", "taskRecurringSchedule.nextTargetStartDate.mayNotBePast")
+
+            taskInstance.taskRecurringSchedule = result.taskRecurringScheduleInstance
+
+            if(!result.taskRecurringScheduleInstance.save() || !taskInstance.save())
+                return fail()
+
+             // If we get here all went well.
+            return result
+
+        } //end withTransaction
+    } // end create()
+
+    /**
+    * Updates an existing recurring schedule.
+    * @param params The params to update for recurring schedule with id of params.id.
+    * @returns A map containing result.error=true (if any error) and result.taskRecurringScheduleInstance (if available).
+    */
+    def update(params) {
+        TaskRecurringSchedule.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Object[] args ->
+                status.setRollbackOnly()
+                if(args.size() == 2) result.taskRecurringScheduleInstance.errors.rejectValue(args[0], args[1])
+                result.error = true
+                return result
+            }
+
+            result.taskRecurringScheduleInstance = TaskRecurringSchedule.get(params.id)
+
+            if(!result.taskRecurringScheduleInstance)
+                return fail('id', "taskRecurringSchedule.notFound")
+
+            // Optimistic locking check.
+            if(params.version) {
+                def version = params.version.toLong()
+                if(result.taskRecurringScheduleInstance.version > version)
+                    return fail("version", "default.optimistic.locking.failure")
+            }
+
+            result.taskRecurringScheduleInstance.properties = params
+
+            if(result.taskRecurringScheduleInstance.nextTargetStartDate < dateUtilService.today)
+                return fail("nextTargetStartDate", "taskRecurringSchedule.nextTargetStartDate.mayNotBePast")
+
+            result.taskRecurringScheduleInstance.setNextGenerationDate()
+            result.taskRecurringScheduleInstance.setNextTargetCompletionDate()
+
+            if(result.taskRecurringScheduleInstance.hasErrors() || !result.taskRecurringScheduleInstance.save())
+                return fail()
+
+            // If we get here all went well.
+            return result
+
+        } //end withTransaction
+    }  // end update()
+
+} // end of class
Index: /branches/features/grailsUpgrade/grails-app/services/TaskReportService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/TaskReportService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/TaskReportService.groovy	(revision 875)
@@ -0,0 +1,337 @@
+import org.gnumims.RichUiCalendarItem
+
+/**
+* Service class that encapsulates the business logic for Task Reports.
+*/
+class TaskReportService {
+
+    boolean transactional = false
+
+    def authService
+    def dateUtilService
+//     def messageSource
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    def paramsMax = 100000
+
+    /**
+    * Selects and returns the reactive ratio.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getReactiveRatio(params, locale) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: [] ]
+            return result
+        }
+
+        def namedParams = [:]
+        namedParams.startDate = params.startDate ?: dateUtilService.today
+        namedParams.endDate = params.endDate ?: dateUtilService.today
+
+        // Auto swap date range.
+        if(namedParams.startDate > namedParams.endDate) {
+            def tempStartDate = namedParams.startDate
+            namedParams.startDate = namedParams.endDate
+            namedParams.endDate = tempStartDate
+        }
+
+        result.startDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: namedParams.startDate)
+        result.endDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: namedParams.endDate)
+
+        namedParams.endDate++ // Start of next day required.
+
+        namedParams.immediateCallout = TaskType.read(1)
+        namedParams.unscheduledBreakin = TaskType.read(2)
+        namedParams.preventativeMaintenance = TaskType.read(4)
+        namedParams.notStarted = TaskStatus.read(1)
+
+        result.taskQuery = "from Task as task \
+                                            where (task.trash = false \
+                                                        and task.taskStatus != :notStarted \
+                                                        and task.targetStartDate < :endDate \
+                                                        and task.targetStartDate >= :startDate \
+                                                        and ( \
+                                                            task.taskType = :immediateCallout \
+                                                            or task.taskType = :unscheduledBreakin \
+                                                            or task.taskType = :preventativeMaintenance \
+                                                        ) \
+                                            )"
+
+        result.taskQuery = "select distinct task " + result.taskQuery
+        result.taskList = Task.executeQuery(result.taskQuery, namedParams)
+        result.taskCount = result.taskList.size()
+
+        // Assets on Tasks Count.
+        result.totalAssetsOnTasksCount = 0
+        result.immediateCalloutCount = 0
+        result.unscheduledBreakinCount = 0
+        result.preventativeMaintenanceCount = 0
+
+        // Summary Of Calculations.
+        result.summaryOfCalculationMethod = 'HQL query: \n\n'
+        def tempStringArray = result.taskQuery.split('    ')
+        tempStringArray.each() {
+            if(it != '') result.summaryOfCalculationMethod += it +'\n'
+        }
+        result.summaryOfCalculationMethod += '\n'+'Calculations: '+'\n\n'
+
+        result.summaryOfCalculationMethod += 'totalAssetsOnTasksCount = A count of unique assets on each task. \n'
+        result.taskList.each() { task ->
+            if(task.primaryAsset) {
+                result.totalAssetsOnTasksCount++
+                if(task.taskType == namedParams.immediateCallout) result.immediateCalloutCount++
+                if(task.taskType == namedParams.unscheduledBreakin) result.unscheduledBreakinCount++
+                if(task.taskType == namedParams.preventativeMaintenance) result.preventativeMaintenanceCount++
+            }
+            task.associatedAssets.each() { associatedAsset ->
+                if(associatedAsset.id != task.primaryAsset?.id) {
+                    result.totalAssetsOnTasksCount++
+                    if(task.taskType == namedParams.immediateCallout) result.immediateCalloutCount++
+                    if(task.taskType == namedParams.unscheduledBreakin) result.unscheduledBreakinCount++
+                    if(task.taskType == namedParams.preventativeMaintenance) result.preventativeMaintenanceCount++
+                }
+            }
+        } // each() task
+
+        // Percentage of counts.
+        result.immediateCalloutPercentage = 0
+        result.totalPreventativePercentage = 0
+
+        result.summaryOfCalculationMethod += 'totalPreventativeCount = unscheduledBreakinCount + preventativeMaintenanceCount\n'
+        result.totalPreventativeCount = result.unscheduledBreakinCount + result.preventativeMaintenanceCount
+        try {
+            result.summaryOfCalculationMethod += 'immediateCalloutPercentage = (immediateCalloutCount / totalAssetsOnTasksCount)*100 \n'
+            result.summaryOfCalculationMethod += 'totalPreventativePercentage = (totalPreventativeCount / totalAssetsOnTasksCount)*100 \n'
+            result.immediateCalloutPercentage = (result.immediateCalloutCount / result.totalAssetsOnTasksCount)*100
+            result.totalPreventativePercentage = (result.totalPreventativeCount / result.totalAssetsOnTasksCount)*100
+        }
+        catch(ArithmeticException e) {
+            log.info "Could not calculate: Assets on Tasks Percentages: "+e
+        }
+
+        // Work Done.
+        result.immediateCalloutWorkDone = [total:0, hours:0, minutes:0, percentage: new BigDecimal(0)]
+        result.unscheduledBreakinWorkDone = [total:0, hours:0, minutes:0]
+        result.preventativeMaintenanceWorkDone = [total:0, hours:0, minutes:0]
+        result.totalPreventativeWorkDone = [total:0, hours:0, minutes:0, percentage: new BigDecimal(0)]
+        result.totalWorkDone = [total:0, hours:0, minutes:0]
+
+        result.taskList.each() { task ->
+            task.entries.each() { entry ->
+                // Has assets assigned and is Work Done.
+                if( (task.primaryAsset || task.associatedAssets) && entry.entryType.id == 3L ) {
+                        if(task.taskType == namedParams.immediateCallout)
+                            result.immediateCalloutWorkDone.total += (entry.durationHour*60) + entry.durationMinute
+                        if(task.taskType == namedParams.unscheduledBreakin)
+                            result.unscheduledBreakinWorkDone.total += (entry.durationHour*60) + entry.durationMinute
+                        if(task.taskType == namedParams.preventativeMaintenance)
+                            result.preventativeMaintenanceWorkDone.total += (entry.durationHour*60) + entry.durationMinute
+                }
+            } // each() entry
+        } // each() task
+
+        // Work Done hours and minutes.
+        result.immediateCalloutWorkDone.hours = (result.immediateCalloutWorkDone.total / 60).toInteger()
+        result.immediateCalloutWorkDone.minutes = result.immediateCalloutWorkDone.total % 60
+
+        result.unscheduledBreakinWorkDone.hours = (result.unscheduledBreakinWorkDone.total / 60).toInteger()
+        result.unscheduledBreakinWorkDone.minutes = result.unscheduledBreakinWorkDone.total % 60
+
+        result.preventativeMaintenanceWorkDone.hours = (result.preventativeMaintenanceWorkDone.total / 60).toInteger()
+        result.preventativeMaintenanceWorkDone.minutes = result.preventativeMaintenanceWorkDone.total % 60
+
+        // Work Done Totals.
+        result.totalPreventativeWorkDone.total = result.unscheduledBreakinWorkDone.total + result.preventativeMaintenanceWorkDone.total
+        result.totalPreventativeWorkDone.hours = (result.totalPreventativeWorkDone.total / 60).toInteger()
+        result.totalPreventativeWorkDone.minutes = result.totalPreventativeWorkDone.total % 60
+
+        result.totalWorkDone.total = result.immediateCalloutWorkDone.total + result.totalPreventativeWorkDone.total
+        result.totalWorkDone.hours = (result.totalWorkDone.total / 60).toInteger()
+        result.totalWorkDone.minutes = result.totalWorkDone.total % 60
+
+        // Work Done Percentages.
+        try {
+            result.immediateCalloutWorkDone.percentage = (BigDecimal)(result.immediateCalloutWorkDone.total / result.totalWorkDone.total)*100
+            result.totalPreventativeWorkDone.percentage = (BigDecimal)(result.totalPreventativeWorkDone.total / result.totalWorkDone.total)*100
+        }
+        catch(ArithmeticException e) {
+            log.info "Could not calculate: Work Done Percentages: "+e
+        }
+
+        // Success.
+        return result
+
+    } // getReactiveRatio
+
+    /**
+    * Selects and returns Immediate Callouts, grouped by Asset.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getImmediateCallouts(params, locale) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: [] ]
+            return result
+        }
+
+        def namedParams = [:]
+        namedParams.startDate = params.startDate ?: dateUtilService.today
+        namedParams.endDate = params.endDate ?: dateUtilService.today
+
+        // Auto swap date range.
+        if(namedParams.startDate > namedParams.endDate) {
+            def tempStartDate = namedParams.startDate
+            namedParams.startDate = namedParams.endDate
+            namedParams.endDate = tempStartDate
+        }
+
+        result.startDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: namedParams.startDate)
+        result.endDateString = g.formatDate(format: "EEE, dd-MMM-yyyy", date: namedParams.endDate)
+
+        namedParams.endDate++ // Start of next day required.
+
+        namedParams.immediateCallout = TaskType.read(1)
+
+        result.taskQuery = "from Task as task \
+                                            where (task.trash = false \
+                                                        and task.targetStartDate < :endDate \
+                                                        and task.targetStartDate >= :startDate \
+                                                        and task.taskType = :immediateCallout \
+                                                        ) \
+                                            )"
+
+        result.taskQuery = "select distinct task " + result.taskQuery
+        result.taskQueryList = Task.executeQuery(result.taskQuery, namedParams)
+        result.taskCount = result.taskQueryList.size()
+
+        // Assets on Tasks Count.
+        result.totalAssetsOnTasksCount = 0
+        result.totalDownTime = [total: 0, hours: 0, minutes:0]
+        result.assetList = []
+
+        // Task Details
+        result.taskList = []
+
+        // Add or update lists.
+        def addToLists = { asset, task ->
+
+            def downTime = 0
+            def faultEntries = Entry.findAllByTaskAndEntryType(task, EntryType.read(1))
+            def causeEntries = Entry.findAllByTaskAndEntryType(task, EntryType.read(2))
+            def workDoneEntries = Entry.findAllByTaskAndEntryType(task, EntryType.read(3))
+            def taskDetails = 'Task #'+task.id+' - '+task.description+'\n'
+            faultEntries.each(){
+                taskDetails += '    Faults: '+it.comment+' - '+it.enteredBy+', '+g.formatDate(format: "EEE, dd-MMM-yyyy", date: it.dateDone)+'.\n'
+            }
+            causeEntries.each(){
+                taskDetails += '    Causes: '+it.comment+' - '+it.enteredBy+', '+g.formatDate(format: "EEE, dd-MMM-yyyy", date: it.dateDone)+'.\n'
+            }
+            workDoneEntries.each(){
+                taskDetails += '    Work Done: '+it.comment+' - '+it.enteredBy+', '+g.formatDate(format: "EEE, dd-MMM-yyyy", date: it.dateDone)+'.\n'
+            }
+
+            faultEntries.each() { downTime += (it.durationHour*60 + it.durationMinute) }
+            result.totalDownTime.total += downTime
+
+            def assetDetails = result.assetList.find { it.id == asset.id }
+            if(assetDetails) {
+                assetDetails.immediateCalloutCount++
+                assetDetails.downTime += downTime
+                assetDetails.tasks += taskDetails
+            }
+            else {
+                assetDetails = [id: asset.id,
+                                            name: asset.name,
+                                            immediateCalloutCount: 1,
+                                            downTime: downTime,
+                                            tasks: taskDetails]
+
+                result.assetList << assetDetails
+            }
+        } // addAToLists
+
+        // Summary Of Calculations.
+        result.summaryOfCalculationMethod = 'HQL query: \n\n'
+        def tempStringArray = result.taskQuery.split('    ')
+        tempStringArray.each() {
+            if(it != '') result.summaryOfCalculationMethod += it +'\n'
+        }
+        result.summaryOfCalculationMethod += '\n'+'Calculations: '+'\n\n'
+
+        result.summaryOfCalculationMethod += 'totalAssetsOnTasksCount = A count of unique assets on each task. \n'
+        result.taskQueryList.each() { task ->
+            if(task.primaryAsset) {
+                result.totalAssetsOnTasksCount++
+                addToLists(task.primaryAsset, task)
+            }
+            task.associatedAssets.each() { associatedAsset ->
+                if(associatedAsset.id != task.primaryAsset?.id) {
+                    result.totalAssetsOnTasksCount++
+                    addToLists(associatedAsset, task)
+                }
+            }
+
+        } // each() task
+
+        // Sort assetList by callout count.
+        result.assetList.sort {a, b -> b.immediateCalloutCount.compareTo(a.immediateCalloutCount)}
+
+        // Calculate hours and minutes.
+        result.totalDownTime.hours = (result.totalDownTime.total / 60).toInteger()
+        result.totalDownTime.minutes = result.totalDownTime.total % 60
+
+        // Success.
+        return result
+
+    } // getImmediateCallouts()
+
+    /**
+    * Builds and returns a list of RichUiCalendarItem's.
+    * @param params The request params, may contain params to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getWorkLoadSummary(params, locale) {
+
+        def result = [:]
+        result.displayList = []
+
+        def listItem
+
+        def dayMap = [:]
+        def assignedGroupMap = [:]
+
+        params.taskInstanceList.each { task ->
+            def dayKey = task.targetStartDate /// @todo: make this key more stable.
+            def assignedTime = 0
+
+            task.assignedGroups.each{ assignedGroup ->
+                assignedTime = assignedGroup.estimatedHour*60 + assignedGroup.estimatedMinute
+            }
+
+            if(dayMap.containsKey(dayKey)) {
+                if(task.description) {
+                    dayMap[dayKey] = dayMap[dayKey] + assignedTime
+                }
+            }
+            else {
+                dayMap[(dayKey)] = assignedTime
+            }
+        }
+
+        dayMap.each { k, v ->
+                listItem = new RichUiCalendarItem(date:k, text:('assignedTime: '+v.toString()))
+                result.displayList << listItem
+        }
+
+        // Success.
+        return result
+
+    } // getWorkLoadSummary()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/TaskSearchService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/TaskSearchService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/TaskSearchService.groovy	(revision 875)
@@ -0,0 +1,545 @@
+import net.kromhouts.HqlBuilder
+import grails.orm.PagedResultList
+import org.hibernate.FetchMode as FM
+
+/**
+* Service class that encapsulates the business logic for Task searches.
+*/
+class TaskSearchService {
+
+    boolean transactional = false
+
+    def authService
+    def dateUtilService
+    def messageSource
+
+    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
+
+    def paramsMax = 100000
+
+    // Be sure to update taskQuickSearchPane.js if quickSearchSelection is changed.
+    def getQuickSearchSelection() {
+        [ 'allTasks': g.message(code: 'task.search.text.all.tasks'),
+        'personsImmediateCallouts': g.message(code: 'task.search.text.persons.immediate.callouts'),
+        'personsTasks': g.message(code: 'task.search.text.persons.tasks')
+        ]
+    }
+
+    /**
+    * Selects and returns the correct search results based on the supplied quickSearch.
+    * @param params The request params, may contain params.quickSearch string to specify the search.
+    * @param locale The locale to use when generating result.message.
+    */
+    def getQuickSearch(params = [:], locale) {
+        def result = [:]
+        result.quickSearch = params.quickSearch ?: "personsTasks"
+        if(params.person)
+            result.person = Person.get(params.person.id.toLong())
+        else
+            result.person = authService.currentUser
+        result.startDate = params.startDate ?: dateUtilService.today
+        result.endDate = params.endDate ?: dateUtilService.today
+        // Auto swap date range.
+        if(result.startDate > result.endDate) {
+            def tempStartDate = result.startDate
+            result.startDate = result.endDate
+            result.endDate = tempStartDate
+        }
+        result.includeCompleted = params.includeCompleted = params.includeCompleted ? true:false
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        def formatted = { Date d ->
+            g.formatDate(format: "EEE, dd-MMM-yyyy", date: d)
+        }
+
+        def startOfToday = dateUtilService.today
+        def startOfYesterday = dateUtilService.yesterday
+        def startOfTomorrow = dateUtilService.tomorrow
+        def oneWeekAgo = dateUtilService.oneWeekAgo
+
+        def formattedStartOfToday = formatted(startOfToday)
+        def formattedStartOfYesterday = formatted(startOfYesterday)
+        def formattedStartOfTomorrow = formatted(startOfTomorrow)
+        def formattedOneWeekAgo = formatted(oneWeekAgo)
+
+        def allTasks = {
+            result.taskInstanceList = getTasks(params, result.startDate, result.endDate+1)
+            if(result.taskInstanceList.totalCount > 0) {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.all.tasks.message",
+                                                                    args:[ formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.all.tasks.between.message",
+                                                                    args:[ formatted(result.startDate), formatted(result.endDate) ])
+            }
+            else {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.all.tasks.none.found",
+                                                                    args:[ formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.all.tasks.between.none.found",
+                                                                    args:[ formatted(result.startDate), formatted(result.endDate) ])
+            }
+
+        }
+
+        def personsTasks = {
+            result.taskInstanceList = getPersonsTasks(params, result.person, result.startDate, result.endDate+1)
+            if(result.taskInstanceList.totalCount > 0) {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.tasks.message",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.tasks.between.message",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+            else {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.tasks.none.found",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.tasks.between.none.found",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+
+        }
+
+        def personsImmediateCallouts = {
+            result.taskInstanceList = getPersonsImmediateCallouts(params, result.person, result.startDate, result.endDate+1)
+            if(result.taskInstanceList.totalCount > 0) {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.message",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.between.message",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+            else {
+                if(result.startDate == result.endDate)
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.none.found",
+                                                                    args:[ result.person, formatted(result.startDate) ])
+                else
+                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.between.none.found",
+                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
+            }
+
+        }
+
+        switch (result.quickSearch) {
+            case "myTodays":
+                result.quickSearch = "personsTasks"
+                result.startDate = startOfToday
+                result.endDate = startOfToday
+                personsTasks()
+                break
+            case "myYesterdays":
+                result.quickSearch = "personsTasks"
+                result.startDate = startOfYesterday
+                result.endDate = startOfYesterday
+                personsTasks()
+                break
+            case "myTomorrows":
+                result.quickSearch = "personsTasks"
+                result.startDate = startOfTomorrow
+                result.endDate = startOfTomorrow
+                personsTasks()
+                break
+            case "myPastWeek":
+                result.quickSearch = "personsTasks"
+                result.startDate = oneWeekAgo
+                result.endDate = startOfToday
+                personsTasks()
+                break
+            case "personsTasks":
+                personsTasks()
+                break
+            case "personsImmediateCallouts":
+                personsImmediateCallouts()
+                break
+            case "todays":
+                result.quickSearch = "allTasks"
+                result.startDate = startOfToday
+                result.endDate = startOfToday
+                allTasks()
+                break
+            case "yesterdays":
+                result.quickSearch = "allTasks"
+                result.startDate = startOfYesterday
+                result.endDate = startOfToday
+                allTasks()
+                break
+            case "tomorrows":
+                result.quickSearch = "allTasks"
+                result.startDate = startOfTomorrow
+                result.endDate = startOfTomorrow+1
+                allTasks()
+                break
+            case "pastWeek":
+                result.quickSearch = "allTasks"
+                result.startDate = oneWeekAgo
+                result.endDate = startOfTomorrow
+                allTasks()
+                break
+            case "allTasks":
+                allTasks()
+                break
+            default:
+                //case "plannersRange":
+                result.quickSearch = "allTasks"
+                result.startDate = oneWeekAgo
+                result.endDate = startOfToday+15
+                allTasks()
+                break
+        } // switch.
+
+        // Success.
+        return result
+
+    } // getQuickSearch
+
+    /**
+    * Get all tasks that are not in the trash bin, by default today's tasks.
+    * @param params The request params.
+    * @param startDate The start date to get tasks for, defaults to the start of today and is inclusive (greater than or equal to).
+    * @param endDate The end date to get tasks for, defaults to the start of tomorrow and is exclusive (less than).
+    */
+    def getTasks(params, startDate=null, endDate=null) {
+        def paginateParams = [:]
+        paginateParams.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        paginateParams.offset = params?.offset?.toInteger() ?: 0
+
+        def orderBy = ''
+        if(params.sort?.contains('.')) // protect against filterpane bug.
+            params.sort = null
+        if(params.sort && params.order) {
+            def sort = "task." + params.sort
+            def order = (params.order == "asc") ? "asc" : "desc"
+            orderBy = " order by " + sort + ' ' + order
+        }
+        else
+            orderBy = " order by task.taskStatus, task.taskPriority, task.targetStartDate"
+
+        def namedParams = [:]
+        namedParams.startDate = startDate ?: dateUtilService.today
+        namedParams.endDate = endDate ?: dateUtilService.tomorrow
+
+        def baseQuery = "from Task as task \
+                                        where (task.trash = false \
+                                                    and task.targetStartDate < :endDate \
+                                                    and task.targetCompletionDate >= :startDate \
+                                        )"
+
+        def searchQuery = "select distinct task " + baseQuery + orderBy
+        def list = Task.executeQuery(searchQuery, namedParams, paginateParams)
+
+        def countQuery = "select count(distinct task) as taskCount " + baseQuery
+        def totalCount = Task.executeQuery(countQuery, namedParams)[0].toInteger()
+
+        def taskInstanceList = new PagedResultList(list, totalCount)
+        return taskInstanceList
+    } // getTasks()
+
+    /**
+    * Get a person's tasks, by default current user and today's tasks.
+    * "My tasks and approved tasks that I am assigned to"
+    * @param params The request params.
+    * @param person The person to get tasks for, defaults to current user.
+    * @param startDate The start date to get tasks for, defaults to the start of today and is inclusive (greater than or equal to).
+    * @param endDate The end date to get tasks for, defaults to the start of tomorrow and is exclusive (less than).
+    */
+    def getPersonsTasks(params, person=null, startDate=null, endDate=null) {
+
+        def max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        def offset = params?.offset?.toInteger() ?: 0
+
+        def orderBy = ''
+        if(params.sort?.contains('.')) // protect against filterpane bug.
+            params.sort = null
+        if(params.sort && params.order) {
+            def sort = "task." + params.sort
+            def order = (params.order == "asc") ? "asc" : "desc"
+            orderBy = "by " + sort + ' ' + order
+        }
+        else
+            orderBy = "by task.taskPriority, task.targetStartDate, task.taskStatus"
+
+        def q = new HqlBuilder().query {
+
+            select 'count(distinct task) as taskCount'
+            from 'Task as task',
+                    'left join task.assignedPersons as assignedPersonOfTask',
+                    'left join assignedPersonOfTask.person as assignedPerson',
+                    'left join task.assignedGroups as assignedGroupOfTask',
+                    'left join assignedGroupOfTask.personGroup as personGroup',
+                    'left join personGroup.persons as assignedPersonViaGroup',
+                    'left join task.taskModifications as taskModification',
+                    'left join taskModification.person as createdBy',
+                    'left join taskModification.taskModificationType as taskModificationType'
+            where 'task.trash = false'
+                    and 'task.targetStartDate < :endDate'
+                    and 'task.targetCompletionDate >= :startDate'
+                    if(!params.includeCompleted) {
+                        and 'task.taskStatus.id != 3' // Complete.
+                    }
+                    and {
+                        where '(taskModificationType.id = 1 and createdBy = :person and task.leadPerson = :person)' // Created.
+                        or '(task.approved = true and (task.leadPerson = :person or assignedPerson = :person or assignedPersonViaGroup = :person))'
+                    }
+        }
+
+        q.namedParams.person = person ?: authService.currentUser
+        q.namedParams.startDate = startDate ?: dateUtilService.today
+        q.namedParams.endDate = endDate ?: dateUtilService.tomorrow
+
+        def totalCount = Task.executeQuery(q.query, q.namedParams)[0].toInteger()
+
+        q.select = "distinct task"
+        q.order = orderBy
+        q.paginateParams.max = max
+        q.paginateParams.offset = offset
+        def list = Task.executeQuery(q.query, q.namedParams, q.paginateParams)
+
+        def taskInstanceList = new PagedResultList(list, totalCount)
+        return taskInstanceList
+    } // getPersonsTasks()
+
+    /**
+    * Get a person's immediateCallout tasks, by default all users and today's tasks.
+    * @param params The request params.
+    * @param person The person to get tasks for, defaults to null and therefore all immediateCallouts.
+    * @param startDate The start date to get tasks for, defaults to the start of today and is inclusive (greater than or equal to).
+    * @param endDate The end date to get tasks for, defaults to the start of tomorrow and is exclusive (less than).
+    */
+    def getPersonsImmediateCallouts(params, person=null, startDate=null, endDate=null) {
+
+        def max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
+        def offset = params?.offset?.toInteger() ?: 0
+
+        def orderBy = ''
+        if(params.sort?.contains('.')) // protect against filterpane bug.
+            params.sort = null
+        if(params.sort && params.order) {
+            def sort = "task." + params.sort
+            def order = (params.order == "asc") ? "asc" : "desc"
+            orderBy = "by " + sort + ' ' + order
+        }
+        else
+            orderBy = "by task.taskStatus, task.targetStartDate"
+
+        def q = new HqlBuilder().query {
+
+            select 'count(distinct task) as taskCount'
+            from 'Task as task',
+                    'left join task.taskModifications as taskModification',
+                    'left join taskModification.person as createdBy',
+                    'left join taskModification.taskModificationType as taskModificationType'
+            where 'task.taskType.id = 1' // Immediate Callout.
+                    and 'task.targetStartDate < :endDate'
+                    and 'task.targetCompletionDate >= :startDate'
+                    if(!params.includeCompleted) {
+                        and 'task.taskStatus.id != 3' // Complete.
+                    }
+                    if(person) {
+                        namedParams.person = person
+                        and '( (taskModificationType.id = 1 and createdBy = :person) or task.leadPerson = :person)' // Created or Lead Person.
+                    }
+                    and 'task.trash = false'
+        }
+
+        q.namedParams.startDate = startDate ?: dateUtilService.today
+        q.namedParams.endDate = endDate ?: dateUtilService.tomorrow
+
+        def totalCount = Task.executeQuery(q.query, q.namedParams)[0].toInteger()
+
+        q.select = "distinct task"
+        q.order = orderBy
+        q.paginateParams.max = max
+        q.paginateParams.offset = offset
+        def list = Task.executeQuery(q.query, q.namedParams, q.paginateParams)
+
+        def taskInstanceList = new PagedResultList(list, totalCount)
+        return taskInstanceList
+    } // getPersonsImmediateCallouts()
+
+    /**
+    * Get work done by person and date.
+    * A person ID and date may be specified in params otherwise the current user and today are used.
+    * @param params The request params.
+    * @returns A map containing entries, totalEntries, startOfDay, person, totalHours, totalMinutes.
+    */
+    def getWorkDone(params, locale) {
+        def result = [:]
+        result.person = params.person?.id ? Person.get(params.person.id.toInteger()) : authService.currentUser
+
+        if(params.date_year && params.date_month && params.date_day)
+            result.startOfDay = dateUtilService.makeDate(params.date_year, params.date_month, params.date_day)
+        else
+            result.startOfDay = dateUtilService.today
+
+        result.startOfNextDay = result.startOfDay + 1
+
+        def formattedStartOfDay = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startOfDay)
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        result.entries = Entry.createCriteria().list() {
+            eq("enteredBy", result.person)
+            ge("dateDone", result.startOfDay)
+            lt("dateDone", result.startOfNextDay)
+            entryType {
+                or {
+                    idEq(3L) // Work Done.
+                    idEq(6L) // PM Entry.
+                }
+            }
+        } // createCriteria
+
+        result.totalEntries = result.entries.size()
+
+        if(result.totalEntries > 0)
+            result.message = getMessage(code:"task.search.text.work.done.message",
+                                                                args:[result.person, formattedStartOfDay])
+        else
+            result.message = getMessage(code:"task.search.text.work.done.none.found",
+                                                                args:[result.person, formattedStartOfDay])
+
+        result.totalHours = 0
+        result.totalMinutes = 0
+        result.entries.each() {
+            result.totalMinutes += (it.durationHour*60) + it.durationMinute
+        }
+        result.totalHours = (result.totalMinutes / 60).toInteger()
+        result.totalMinutes = result.totalMinutes % 60
+
+        return result
+    } // getWorkDone()
+
+    /**
+    * Get work load by task group and date.
+    * Group ID's and date range may be specified in params otherwise no group and today are used.
+    * @param params The request params.
+    * @returns A map containing the results.
+    */
+    def getWorkLoad(params, locale) {
+        def result = [:]
+        def max = 1000
+
+        // TaskStatus..
+        result.taskStatusList = []
+        if(params.taskStatusList instanceof String)
+            result.taskStatusList << TaskStatus.get(params.taskStatusList.toInteger())
+        else if(params.taskStatusList)
+            result.taskStatusList = TaskStatus.getAll( params.taskStatusList.collect {it.toInteger()} )
+
+        // TaskGroups.
+        result.taskGroups = []
+        if(params.taskGroups instanceof String)
+            result.taskGroups << TaskGroup.get(params.taskGroups.toInteger())
+        else if(params.taskGroups)
+            result.taskGroups = TaskGroup.getAll( params.taskGroups.collect {it.toInteger()} )
+
+        // Start Date.
+        if(params.startDate_year && params.startDate_month && params.startDate_day)
+            result.startDate = dateUtilService.makeDate(params.startDate_year, params.startDate_month, params.startDate_day)
+        else
+            result.startDate = dateUtilService.today
+
+        // End Date.
+        if(params.endDate_year && params.endDate_month && params.endDate_day)
+            result.endDate = dateUtilService.makeDate(params.endDate_year, params.endDate_month, params.endDate_day)
+        else
+            result.endDate = result.startDate
+
+        // Auto swap date range.
+        if(result.startDate > result.endDate) {
+            def tempStartDate = result.startDate
+            result.startDate = result.endDate
+            result.endDate = tempStartDate
+        }
+
+        def formattedStartDate = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startDate)
+        def formattedEndDate = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.endDate)
+
+        def getMessage = { Map m ->
+            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
+        }
+
+        result.tasks = new PagedResultList([], 0)
+
+        if(result.taskGroups && result.taskStatusList) {
+
+            result.tasks = Task.createCriteria().list(max: max) {
+                eq("trash", false)
+                lt("targetStartDate", result.endDate+1)
+                ge("targetCompletionDate", result.startDate)
+                inList("taskStatus", result.taskStatusList)
+                inList("taskGroup", result.taskGroups)
+                order("taskStatus", "asc")
+                order("taskPriority", "asc")
+                order("targetStartDate", "asc")
+                fetchMode("assignedGroups", FM.EAGER)
+                fetchMode("assignedGroups.personGroup", FM.EAGER)
+            } // createCriteria
+
+        }
+
+        result.tasks.list.unique()
+        result.totalHours = 0
+        result.totalMinutes = 0
+        result.workLoadGroups = [:]
+
+        // Exit early!
+        if(result.tasks.totalCount > result.tasks.size()) {
+            result.errorMessage = getMessage(code:"task.search.text.work.load.too.many.results",
+                                                                args:[result.tasks.size(), result.tasks.totalCount])
+            return result
+        }
+        else if(result.tasks.size() > 0)
+            result.message = getMessage(code:"task.search.text.work.load.message",
+                                                                args:[formattedStartDate, formattedEndDate])
+        else
+            result.message = getMessage(code:"task.search.text.work.load.none.found",
+                                                                args:[formattedStartDate, formattedEndDate])
+
+        // Collect all assignedGroups.
+        def assignedGroups = []
+        for(task in result.tasks) {
+            for(assignedGroup in task.assignedGroups) {
+                assignedGroups << assignedGroup
+            }
+        }
+
+        // Calculate work load for each personGroup and minute totals.
+        def tempHours = 0
+        def tempMinutes = 0
+        def personGroup
+        for(assignedGroup in assignedGroups) {
+            personGroup = assignedGroup.personGroup
+            if(!result.workLoadGroups.containsKey(personGroup)) {
+                result.workLoadGroups[personGroup] = [hours: 0, minutes: 0]
+            }
+
+            tempMinutes = (assignedGroup.estimatedHour*60) + assignedGroup.estimatedMinute
+            result.totalMinutes += tempMinutes
+            result.workLoadGroups[personGroup].minutes += tempMinutes
+        }
+
+        // Resolve totals and sort.
+        result.workLoadGroups.each { workLoadGroup ->
+            workLoadGroup.value.hours =  (workLoadGroup.value.minutes / 60).toInteger()
+            workLoadGroup.value.minutes = workLoadGroup.value.minutes % 60
+        }
+        result.workLoadGroups = result.workLoadGroups.sort { p1, p2 -> p1.key.name.compareToIgnoreCase(p2.key.name) }
+        result.totalHours = (result.totalMinutes / 60).toInteger()
+        result.totalMinutes = result.totalMinutes % 60
+
+        // Success.
+        return result
+    } // getWorkLoad()
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/services/TaskService.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/services/TaskService.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/services/TaskService.groovy	(revision 875)
@@ -0,0 +1,1098 @@
+import grails.util.Environment
+
+/**
+* Provides a service class for the Task domain class.
+*
+*/
+class TaskService {
+
+    boolean transactional = false
+
+    def authService
+    def dateUtilService
+    def authenticateService
+    def assignedGroupService
+    def assignedPersonService
+
+    /**
+    * Determines and returns a possible parent list for a task.
+    * @todo Create and use another method that limits the results to say the latest 20 or 100 tasks?
+    * @param taskInstance The task to use when determining the possible parent list.
+    * @returns A list of the possible parents.
+    */
+    def possibleParentList(taskInstance) {
+        def criteria = taskInstance.createCriteria()
+        def possibleParentList = criteria {
+            and {
+                notEqual('trash', true)
+                notEqual('id', taskInstance.id)
+                taskInstance.subTasks.each() { notEqual('id', it.id) }
+                }
+        }
+    }
+
+    /**
+    * Determines and returns a list of possible task types for scheduled tasks.
+    * @returns A list of the possible task types.
+    */
+    def getScheduledTaskTypes() {
+        def criteria = TaskType.createCriteria()
+        def scheduledTaskTypes = criteria {
+            and {
+                eq('isActive', true)
+                gt('id', 2L)
+                }
+        }
+    }
+
+    /**
+    * Determines and returns a list of parentPM tasks for an asset.
+    * @param asset The asset to get parentPM tasks for.
+    * @returns A list of the possible task types.
+    */
+    def getParentPMs(asset) {
+        def parentPMs = Task.withCriteria {
+                                                eq("primaryAsset", asset)
+                                                taskType {
+                                                    idEq(6L)
+                                                }
+                                                maxResults(1000)
+                                        }
+    }
+
+    /**
+    * Determines and returns a list of possible task priorites for Scheduled tasks.
+    * @returns A list of the possible task priorites.
+    */
+    def getScheduledTaskPriorities() {
+        def criteria = TaskPriority.createCriteria()
+        def scheduledTaskPriorities = [:]
+        scheduledTaskPriorities.list = criteria {
+            and {
+                eq('isActive', true)
+                gt('id', 1L)
+                }
+        }
+        scheduledTaskPriorities.default = scheduledTaskPriorities.list.find { it.id == 4L } //  1-Normal.
+        return scheduledTaskPriorities
+    }
+
+    /**
+    * Determines and returns a list of possible task priorites for Unscheduled tasks.
+    * @returns A map containing a list of the possible task priorites and the default priority.
+    */
+    def getUnscheduledTaskPriorities() {
+        def criteria = TaskPriority.createCriteria()
+        def unscheduledTaskPriorities = [:]
+        unscheduledTaskPriorities.list = criteria {
+            and {
+                eq('isActive', true)
+                lt('id', 5L)
+                ne('id', 1L)
+            }
+        }
+        unscheduledTaskPriorities.default = unscheduledTaskPriorities.list.find { it.id == 3L } // 2-High.
+        return unscheduledTaskPriorities
+    }
+
+    /**
+    * Creates a new task with the given params.
+    * @param params The params to use when creating the new task.
+    * @returns A map containing result.error (if any error) and result.taskInstance.
+    */
+    def save(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            def taskInstance = new Task(params)
+            result.taskInstance = taskInstance
+
+            // Set taskStatus if not supplied.
+            if(!params.taskStatus)
+                taskInstance.taskStatus = TaskStatus.read(1) // Not Started
+
+            // Set budgetStatus if not supplied.
+            if(!params.taskBudgetStatus) {
+                if(taskInstance.taskType?.id == 1 || taskInstance.taskType?.id == 2) // Immediate Callout or Unsheduled Breakin.
+                    taskInstance.taskBudgetStatus = TaskBudgetStatus.read(1) // Unplanned.
+                else
+                    taskInstance.taskBudgetStatus = TaskBudgetStatus.read(2) // Planned.
+            }
+
+            if(result.taskInstance.parentTask?.trash)
+                return fail(field:"parentTask", code:"task.operationNotPermittedOnTaskInTrash")
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.create.failure")
+
+            def taskModification = new TaskModification(person: authService.currentUser,
+                                                taskModificationType: TaskModificationType.get(1),
+                                                task: taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(field:"taskModifications", code:"task.modifications.failedToSave")
+
+            //Add the assignedGroups, provided by a new ArrayList(task.assignedGroups)
+            if(params.assignedGroups) {
+                def assignedGroupsResult
+                def assignedGroupParams = [:]
+                params.assignedGroups.each() {
+
+                    assignedGroupParams = [personGroup: it.personGroup,
+                                                                task: taskInstance,
+                                                                estimatedHour: it.estimatedHour,
+                                                                estimatedMinute: it.estimatedMinute]
+
+                    assignedGroupsResult = assignedGroupService.save(assignedGroupParams)
+
+                    if(assignedGroupsResult.error)
+                        return fail(field:"assignedGroups", code:"task.assignedGroups.failedToSave")
+
+                }
+            }
+
+            //Add the assignedPersons, provided by a new ArrayList(task.assignedPersons)
+            if(params.assignedPersons) {
+                def assignedPersonsResult
+                def assignedPersonsParams = [:]
+                params.assignedPersons.each() {
+
+                    assignedPersonsParams = [person: it.person,
+                                                                task: taskInstance,
+                                                                estimatedHour: it.estimatedHour,
+                                                                estimatedMinute: it.estimatedMinute]
+
+                    assignedPersonsResult = assignedPersonService.save(assignedPersonsParams)
+
+                    if(assignedPersonsResult.error)
+                        return fail(field:"assignedPersons", code:"task.assignedPersons.failedToSave")
+
+                }
+            }
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    } // end save()
+
+    /**
+    * Creates a subTask copying sane attributes from the parentTask unless otherwise specified in params.
+    * The targetStartDate and targetCompletionDate default to today since that is the sane thing to do.
+    * The taskProcedureRevision is only assigned to the sub task if supplied in params.
+    * The assignedPersons and assignedGroups are only added to the sub task if supplied in params.
+    * The positiveFault property is never set on the subTask.
+    * Collections in params must be supplied as new ArrayList's.
+    * This method is not intended to be a copyTask method.
+    * There should be no reason to copy tasks, recurrence can be used to create similar tasks.
+    * @param parentTask The parent task to get attributes from, also set as the parent.
+    * @param params Overrides the parent task values if specified.
+    * @returns A map containing result.error=true (if any error) and result.taskInstance.
+    */
+    def createSubTask(parentTask, params = [:]) {
+
+        def result = [:]
+
+        //Make our new Task a subTask and set the required properties.
+        def p = [:]
+        p.parentTask = parentTask
+        p.description = params.description ?: parentTask.description
+        p.comment = params.comment ?: parentTask.comment
+        p.targetStartDate = params.targetStartDate ?: dateUtilService.today
+        p.targetCompletionDate = params.targetCompletionDate ?: dateUtilService.today
+
+        p.safetyRequirement = params.safetyRequirement ?: parentTask.safetyRequirement
+        p.regulatoryRequirement = params.regulatoryRequirement ?: parentTask.regulatoryRequirement
+        p.mandatoryRequirement = params.mandatoryRequirement ?: parentTask.mandatoryRequirement
+
+        p.taskGroup = params.taskGroup ?: parentTask.taskGroup
+        p.taskStatus = TaskStatus.get(1) // A new subTask must always be "Not Started".
+        p.taskPriority = parentTask.taskPriority
+
+        p.taskType = params.taskType ?: parentTask.taskType
+         // Convert "Parent PM" tasks to "Preventative Maintenance" tasks.
+        if(p.taskType.id == 6)
+            p.taskType = TaskType.get(4)
+
+        p.leadPerson = params.leadPerson ?: parentTask.leadPerson
+        p.primaryAsset = params.primaryAsset ?: parentTask.primaryAsset
+        p.associatedAssets = params.associatedAssets ?: new ArrayList(parentTask.associatedAssets) // Collection.
+
+        // Supplied by recurring tasks.
+        if(params.taskProcedureRevision) p.taskProcedureRevision = params.taskProcedureRevision
+        if(params.assignedGroups) p.assignedGroups = params.assignedGroups // Collection.
+        if(params.assignedPersons) p.assignedPersons = params.assignedPersons // Collection.
+
+        // trash: A new subTask must always have trash=false, which is already the domain class default.
+
+        // These would be considered copying, hence not done.
+        // taskRecurringSchedule, entries, taskModifications, subTasks, inventoryMovements.
+
+        // Create the sub task and return the result.
+        result = save(p)
+
+        // Approve.
+        if(!result.error && parentTask.approved) {
+            p = [:]
+            p.id = result.taskInstance.id
+            approve(p)
+        }
+
+        // Success.
+        return result
+
+    } // end createSubTask()
+
+    /**
+    * In production tasks are NEVER deleted, only the trash flag is set!
+    * However during testing it may be required to delete a task and that
+    * is why this method exists.
+    */
+    def delete(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            if(Environment.current == Environment.PRODUCTION)
+                return fail(code:"task.delete.failure.production")
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Handle taskModifications.
+            def taskModifications = TaskModification.findAllByTask(result.taskInstance)
+            taskModifications.each() {
+                result.taskInstance.removeFromTaskModifications(it)
+                it.delete()
+            }
+
+            // Handle assignedPersons.
+            def taskAssignedPersons = AssignedPerson.findAllByTask(result.taskInstance)
+            taskAssignedPersons.each() {
+                result.taskInstance.removeFromAssignedPersons(it)
+                it.delete()
+            }
+
+            // Handle assignedGroups.
+            def taskAssignedGroups = AssignedGroup.findAllByTask(result.taskInstance)
+            taskAssignedGroups.each() {
+                result.taskInstance.removeFromAssignedGroups(it)
+                it.delete()
+            }
+
+            if(result.error)
+                return result
+
+            try {
+                result.taskInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } // end withTransaction
+    } // delete()
+
+    /**
+    * Creates a new task entry.
+    * @param params The params to use when creating the new entry.
+    * @returns A map containing result.error=true (if any error), result.entryInstance and result.taskId.
+    */
+    def saveEntry(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Entry", params.id] ]
+                return result
+            }
+
+            result.entryInstance = new Entry(params)
+            result.entryInstance.enteredBy = authService.currentUser
+
+            def taskInstance
+            if(result.entryInstance.task?.id) {
+                result.taskId = result.entryInstance.task.id
+                taskInstance = Task.lock(result.entryInstance.task.id)
+            }
+
+            // Check if we should create this entry.
+            def checkResult = checkCreateEntry(result.entryInstance)
+            if(checkResult.error)
+                return fail(field:"task", code: checkResult.error.code)
+
+            if(result.entryInstance.hasErrors() || !result.entryInstance.save())
+                return fail(code:"default.create.failure")
+
+            // If task status is "Not Started"
+            // and entry type is "Work Done" or "PM Entry"
+            // and time has been booked.
+            // Then we create the started modification and set task status.
+            if(taskInstance.taskStatus.id == 1
+                && (result.entryInstance.entryType.id == 3 || result.entryInstance.entryType.id == 6)
+                && (result.entryInstance.durationHour + result.entryInstance.durationMinute > 0)) {
+
+                // Create the "Started" task modification, this provides the "Actual Started Date".
+                def taskModification = new TaskModification(person: authService.currentUser,
+                                                        taskModificationType: TaskModificationType.read(2),
+                                                        task: taskInstance)
+
+                if(taskModification.hasErrors() || !taskModification.save())
+                    return fail(field:"task", code:"task.modifications.failedToSave")
+
+                // Set task status to "In Progress".
+                taskInstance.taskStatus = TaskStatus.read(2)
+            }
+
+            // If PM Entry update task.highestSeverity
+            if(result.entryInstance.entryType.id == 6) {
+                def clist = []
+                taskInstance.entries.each { entry ->
+                    if(entry.entryType.id == 6)
+                        clist << entry.highestSeverity
+                }
+
+                if(clist)
+                    taskInstance.highestSeverity = clist.sort{p1,p2 -> p2.id <=> p1.id}[0]
+            }
+
+            if(taskInstance.hasErrors() || !taskInstance.save())
+                return fail(field:"task", code:"task.failedToSave")
+
+
+            if(params.submitAction) {
+                def actionResult
+                def submit_andSetAttentionFlag = {
+                    actionResult = setAttentionFlag(taskInstance)
+                    if(actionResult.error)
+                        return fail(field:"task", code:actionResult.error.code)
+                }
+                def submit_andComplete = {
+                    actionResult = complete(taskInstance)
+                    if(actionResult.error)
+                        return fail(field:"task", code:actionResult.error.code)
+                }
+
+                switch (params.submitAction) {
+                    case "submit_default":
+                        break
+                    case "submit_andSetAttentionFlag":
+                        submit_andSetAttentionFlag()
+                        break
+                    case "submit_andComplete":
+                        submit_andComplete()
+                        break
+                    default:
+                        break
+                } // switch.
+                if(result.error)
+                    return result
+            } // params.submitAction
+
+            // Success.
+            return result
+
+        } // end withTransaction
+    } // end saveEntry()
+
+    /**
+    * Updates an existing task.
+    * @param params The params to update for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def update(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail('id', "task.notFound")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            result.taskInstance.properties = params
+
+            if(result.taskInstance.taskProcedureRevision?.maintenanceActions && result.taskInstance.isDirty('primaryAsset'))
+                return fail(field:'primaryAsset', code:"tast.operationNotPermittedToChangeAssetWithMaintenanceActions")
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(3),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end update()
+
+    /**
+    * Completes an existing task.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def complete(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            result.taskInstance.taskStatus = TaskStatus.get(3)
+            result.taskInstance.attentionFlag = false
+            result.taskInstance.taskRecurringSchedule?.enabled = false
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(4),
+                                                    task: result.taskInstance)
+
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end complete()
+
+    /**
+    * Sets the attentionFlag on an existing task.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def setAttentionFlag(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            result.taskInstance.attentionFlag = true
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(12),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end flag()
+
+    /**
+    * Clears the attentionFlag on an existing task.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def clearAttentionFlag(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            result.taskInstance.attentionFlag = false
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(13),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end clearFlag()
+
+    /**
+    * Reopens an existing task.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def reopen(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            def isInProgress = false
+            result.taskInstance.entries.each() {
+                if(it.entryType.id == 3 && (it.durationHour + it.durationMinute > 0) )
+                    isInProgress = true
+            }
+
+            if(isInProgress)
+                result.taskInstance.taskStatus = TaskStatus.read(2) // In Progress
+            else
+                result.taskInstance.taskStatus = TaskStatus.read(1) // Not Started
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(5),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end reopen()
+
+    /**
+    * Move a task to the trash.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def trash(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            // Check for authorisation on tasks having subTasks.
+            if(result.taskInstance.subTasks) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"subTasks", code:"task.operationNotPermittedOnTaskHavingSubTasksWithoutAuth")
+            }
+
+            // Check for taskProcedureRevision using this task as linkedTask.
+            if(result.taskInstance.taskProcedureRevision?.linkedTask?.id == result.taskInstance.id) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskProcedureRevision", code:"task.operationNotPermittedOnTaskLinkedToProcedureWithoutAuth")
+            }
+
+            // Check for Parent PM task type.
+            if(result.taskInstance.taskType.id == 6)
+                return fail(field:"taskType", code:"task.operationNotPermittedOnParentPmTask")
+
+            result.taskInstance.trash = true
+            result.taskInstance.attentionFlag = false
+            result.taskInstance.taskRecurringSchedule?.enabled = false
+            result.taskInstance.subTasks.each {
+                it.parentTask = null
+            }
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(6),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end trash()
+
+    /**
+    * Restore a task from the trash.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def restore(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            result.taskInstance.trash = false
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(7),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end restore()
+
+    /**
+    * Approve a task.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def approve(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            result.taskInstance.approved = true
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(8),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end approve()
+
+    /**
+    * Remove a previously given approval from a task.
+    * @param params The params for task with id of params.id.
+    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
+    */
+    def renegeApproval(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            result.taskInstance = Task.get(params.id)
+
+            if(!result.taskInstance)
+                return fail(code:"default.not.found")
+
+            // Optimistic locking check.
+            if(params.version) {
+                if(result.taskInstance.version > params.version.toLong())
+                    return fail(field:"version", code:"default.optimistic.locking.failure")
+            }
+
+            // Check for authorisation on recurring tasks.
+            if(result.taskInstance.taskRecurringSchedule) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskRecurringSchedule", code:"task.operationNotPermittedOnRecurringTaskWithoutAuth")
+            }
+
+            result.taskInstance.approved = false
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                return fail(code:"default.update.failure")
+
+            def taskModification = new TaskModification(person:authService.currentUser,
+                                                    taskModificationType: TaskModificationType.get(9),
+                                                    task: result.taskInstance)
+
+            if(taskModification.hasErrors() || !taskModification.save())
+                return fail(code:"task.modifications.failedToSave")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    }  // end renegeApproval()
+
+    /**
+    * Creates a new unscheduled breakin task with the given params.
+    * @param params The params to use when creating the new task.
+    * @returns A map containing result.error (if any error) and result.taskInstance.
+    */
+    def saveUnscheduled(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            // If not supplied.
+            if(!params.taskStatus)
+                params.taskStatus = TaskStatus.get(1) // Not Started.
+
+            result.taskInstance = new Task(params)
+
+            // Always for an unscheduled breakin..
+            result.taskInstance.taskType = TaskType.get(2) // Unscheduled Breakin.
+            result.taskInstance.taskBudgetStatus = TaskBudgetStatus.get(1) // Unplanned.
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                fail(code:"default.create.failure")
+
+            if(!result.error) {
+                def taskModification = new TaskModification(person: authService.currentUser,
+                                                                taskModificationType: TaskModificationType.get(1), // Created.
+                                                                task: result.taskInstance)
+
+                if(taskModification.hasErrors() || !taskModification.save())
+                    fail(field:"taskModifications", code:"task.modifications.failedToSave")
+            }
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    } // end saveUnscheduled()
+
+    /**
+    * Creates a new immediate callout task with the given params.
+    * @param params The params to use when creating the new task.
+    * @returns A map containing result.error (if any error) and result.taskInstance.
+    */
+    def saveImmediateCallout(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            // If not supplied.
+            if(!params.taskStatus)
+                params.taskStatus = TaskStatus.get(1) // Not Started.
+
+            result.taskInstance = new Task(params)
+
+            // Always for an immediate callout.
+            result.taskInstance.taskType = TaskType.get(1) // Immediate Callout.
+            result.taskInstance.taskBudgetStatus = TaskBudgetStatus.get(1) // Unplanned.
+            result.taskInstance.taskPriority = TaskPriority.get(1) // Immediate.
+            result.taskInstance.taskGroup = TaskGroup.get(1) // Engineering Activites.
+            result.taskInstance.approved = true
+            result.taskInstance.leadPerson = authService.currentUser
+            result.taskInstance.targetCompletionDate = result.taskInstance.targetStartDate
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                fail(code:"default.create.failure")
+
+            if(!result.error) {
+                def taskModification = new TaskModification(person: authService.currentUser,
+                                                                taskModificationType: TaskModificationType.get(1), // Created.
+                                                                task: result.taskInstance)
+
+                if(taskModification.hasErrors() || !taskModification.save())
+                    fail(field:"taskModifications", code:"task.modifications.failedToSave")
+            }
+
+            def productionReference
+            if(params.entryFault.productionReference.id.isLong())
+                productionReference = ProductionReference.get(params.entryFault.productionReference.id.toLong())
+
+            def faultParams = [task: result.taskInstance,
+                                            entryType: EntryType.get(1),
+                                            comment: params.entryFault.comment,
+                                            dateDone: result.taskInstance.targetStartDate,
+                                            productionReference: productionReference,
+                                            durationHour: params.entryFault.durationHour,
+                                            durationMinute: params.entryFault.durationMinute]
+            def faultResult = saveEntry(faultParams)
+            result.entryFaultInstance = faultResult.entryInstance
+
+            def causeParams = [task: result.taskInstance,
+                                            entryType: EntryType.get(2),
+                                            dateDone: result.taskInstance.targetStartDate,
+                                            comment: params.entryCause.comment]
+            def causeResult = saveEntry(causeParams)
+            result.entryCauseInstance = causeResult.entryInstance
+
+            def workDoneParams = [task: result.taskInstance,
+                                                    entryType: EntryType.get(3),
+                                                    comment: params.entryWorkDone.comment,
+                                            dateDone: result.taskInstance.targetStartDate,
+                                                    durationHour: params.entryWorkDone.durationHour,
+                                                    durationMinute: params.entryWorkDone.durationMinute]
+            def workDoneResult = saveEntry(workDoneParams)
+            result.entryWorkDoneInstance = workDoneResult.entryInstance
+
+            if(result.error)
+                return result
+
+            if(causeResult.error)
+                return fail(code: "default.create.failure")
+
+            if(faultResult.error)
+                return fail(code: "default.create.failure")
+
+            if(workDoneResult.error)
+                return fail(code: "default.create.failure")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    } // end saveImmediateCallout()
+
+    /**
+    * Check if we should create an entry.
+    * @param entryInstance The entry to check.
+    * @returns A map containing result.error (if any error) and result.taskInstance.
+    */
+    def checkCreateEntry(entryInstance) {
+        def result = [:]
+
+        def fail = { Map m ->
+            result.error = [ code: m.code, args: [] ]
+            return result
+        }
+
+        def taskInstance = entryInstance.task
+        if(!taskInstance)
+            return fail(code:"task.notFound")
+
+        // Check for tashed task.
+        if(taskInstance.trash)
+            return fail(code:"task.operationNotPermittedOnTaskInTrash")
+
+        // Check for Complete task.
+        if(taskInstance.taskStatus.id == 3)
+            return fail(code: "task.operationNotPermittedOnCompleteTask")
+
+        // Check for recurring schedule.
+        if(taskInstance.taskRecurringSchedule)
+            return fail(code:"task.operationNotPermittedOnRecurringTask")
+
+        // Check for procedure and ensure we are creating a PM Entry.
+        if(taskInstance.taskProcedureRevision && (entryInstance.entryType.id != 6) )
+            return fail(code:"task.createEntryNotPermittedOnTaskWithProcedure")
+
+        // Success.
+        return result
+
+    } // checkCreateEntry()
+
+} // end TaskService
Index: /branches/features/grailsUpgrade/grails-app/taglib/AssetTreeTagLib.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/taglib/AssetTreeTagLib.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/taglib/AssetTreeTagLib.groovy	(revision 875)
@@ -0,0 +1,32 @@
+/**
+* Asset Tree tags.
+* Specific to gnuMims hence the namespace.
+*/
+class AssetTreeTagLib {
+    static namespace = 'gnuMims'
+
+    def js = new JsUtilService()
+    def assetTreeService
+
+    /**
+    * Include required javascript and do setup here.
+    */
+    def resources = { attrs ->
+        out << g.javascript(src: "assetTree.js")
+    }
+
+    /**
+    * Button that opens the asset tree pane and calls the javascript to populate it.
+    */
+    def assetTreeButton = { attrs ->
+        out << assetTreeService.buildAssetTreeButton(attrs)
+    } // assetTreeButton
+
+    /**
+    * The asset tree pane, ready for populating by an ajax call to AssetTreeSevice.
+    */
+    def assetTreePane = { attrs ->
+        out << assetTreeService.buildAssetTreePane(attrs)
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/taglib/CustomTagLib.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/taglib/CustomTagLib.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/taglib/CustomTagLib.groovy	(revision 875)
@@ -0,0 +1,393 @@
+//import org.apache.commons.validator.UrlValidator
+import org.codehaus.groovy.grails.validation.routines.UrlValidator
+import org.codehaus.groovy.grails.validation.routines.RegexValidator
+
+/**
+* General use custom tags.
+* Some are taken from http://www.grails.org/Contribute+a+Tag#checkBoxList
+*/
+class CustomTagLib {
+    static namespace = 'custom'
+
+    private static final Object helpBalloonLockable = new Object();
+    private static long helpBalloonCount = 0L;
+
+    def resources = { attrs ->
+        ///@todo: should include our javascript and do setup here.
+    }
+
+    /**
+    * Checkbox list that can be used as a more user-friendly alternative to a multiselect list box.
+     * Usage:
+     * To map the selected ids to corresponding domain objects,
+     * an additional set method is required in the containing domain class:
+     *       //  This additional setter is used to convert the checkBoxList string or string array
+     *       //  of ids selected to the corresponding domain objects.
+     *       public void setAssetSubItemsFromCheckBoxList(ids) {
+     *           def idList = []
+     *           if(ids instanceof String) {
+     *                   if(ids.isInteger())
+     *                       idList << ids.toInteger()
+     *           }
+     *           else {
+     *               ids.each() {
+     *                   if(it.isInteger())
+     *                       idList << it.toInteger()
+     *               }
+     *           }
+     *           this.assetSubItems = idList.collect { AssetSubItem.get( it ) }
+     *       }
+     *
+     * Then a line in the controller:
+     *      assetInstance.setAssetSubItemsFromCheckBoxList(params.assetSubItems)
+     *
+     * Fields:
+     *    name - the property name.
+     *    from - the list to select from.
+     *    value - the current value.
+     *    optionKey - the key to use.
+     *    sortBy - (optional) the attribute to sort the from list by.
+     *    displayFields - (optional) defaults to the objects toString()
+     *    displayFieldsSeparator - (optional) defaults to a space.
+     *    linkController - (optional, requires linkAction.) the controller to use for a link to the objects in the checkBoxList.
+     *    linkAction - (optional, requires linkController.) the action to use for a link to the objects in the checkBoxList.
+     *
+     * Example:
+     *    <!--
+     *    <custom:checkBoxList name="assetSubItems"
+     *                                    from="${AssetSubItem.list()}"
+     *                                    value="${assetInstance?.assetSubItems.collect{it.id}}"
+     *                                    optionKey="id"
+     *                                    sortBy="description"
+     *                                    displayFields="['id', 'name']"
+     *                                    displayFieldsSeparator=', '
+     *                                    linkController="assetSubItemDetailed"
+     *                                    linkAction="show"/>
+     *    -->
+     *
+     */
+
+    def checkBoxList = {attrs, body ->
+
+        def from = attrs.from
+        def value = attrs.value
+        def cname = attrs.name
+        def isChecked, ht, wd, style, html
+
+        def sortBy = attrs.sortBy
+        def displayFields = attrs.displayFields
+        def displayFieldsSeparator = attrs.displayFieldsSeparator ?: ' '
+        def linkController = attrs.linkController
+        def linkAction = attrs.linkAction
+
+        def displayValue = " "
+
+        // sets the style to override height and/or width if either of them
+        // is specified, else the default from the CSS is taken
+        style = "style='"
+        if(attrs.height)
+            style += "height:${attrs.height};"
+        if(attrs.width)
+            style += "width:${attrs.width};"
+        if(style.length() == "style='".length())
+            style = ""
+        else
+            style += "'" // closing single quote
+
+        html = "<ul class='CheckBoxList' " + style + ">"
+
+        out << html
+
+        if(sortBy)
+            from.sort { p1, p2 -> p1[sortBy].compareToIgnoreCase(p2[sortBy]) }
+
+        from.each { obj ->
+
+            displayValue = " "
+
+            if(linkController && linkAction)
+                   displayValue += "<a href=\"${createLink(controller: linkController, action: linkAction, id: obj.id).encodeAsHTML()}\">"
+
+            if(displayFields) {
+                displayValue += displayFields.collect { obj[it] }.join(displayFieldsSeparator)
+            }
+            else displayValue += obj // use the obj's default toString()
+
+            if(linkController && linkAction)
+                displayValue += "</a>"
+
+            // if we wanted to select the checkbox using a click anywhere on the label (also hover effect)
+            // but grails does not recognize index suffix in the name as an array:
+            // cname = "${attrs.name}[${idx++}]"
+            // and put this inside the li: <label for='$cname'>...</label>
+
+            isChecked = (value?.contains(obj."${attrs.optionKey}"))? true: false
+
+            out << "<li>" << checkBox(name:cname, value:obj."${attrs.optionKey}", checked: isChecked) << displayValue << "</li>"
+        }
+
+        out << "</ul>"
+
+    } // checkBoxList
+
+    def sortableColumnWithImg = { attrs, body ->
+        def writer = out
+        if(!attrs.property)
+            throwTagError("Tag [sortableColumn] is missing required attribute [property]")
+
+//         if(!attrs.title && !attrs.titleKey)
+//             throwTagError("Tag [sortableColumn] is missing required attribute [title] or [titleKey]")
+
+        def property = attrs.remove("property")
+        def action = attrs.action ? attrs.remove("action") : (actionName ?: "list")
+
+        def defaultOrder = attrs.remove("defaultOrder")
+        if(defaultOrder != "desc") defaultOrder = "asc"
+
+        // current sorting property and order
+        def sort = params.sort
+        def order = params.order
+
+        // add sorting property and params to link params
+        def linkParams = [:]
+        if(params.id) linkParams.put("id",params.id)
+        if(attrs.params) linkParams.putAll(attrs.remove("params"))
+        linkParams.sort = property
+
+        // determine and add sorting order for this column to link params
+        attrs.class = (attrs.class ? "${attrs.class} sortable" : "sortable")
+        if(property == sort) {
+            attrs.class = attrs.class + " sorted " + order
+            if(order == "asc")
+                linkParams.order = "desc"
+            else
+                linkParams.order = "asc"
+        }
+        else
+            linkParams.order = defaultOrder
+
+        // determine column title
+//         def title = attrs.remove("title")
+//         def titleKey = attrs.remove("titleKey")
+//         if(titleKey) {
+//             if(!title) title = titleKey
+//             def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")
+//             def locale = RCU.getLocale(request)
+// 
+//             title = messageSource.getMessage(titleKey, null, title, locale)
+//         }
+
+        // Image.
+        def img = "<img "
+        def imgAttrs = [:]
+        imgAttrs.src = attrs.remove("imgSrc")
+        imgAttrs.alt = attrs.remove("imgAlt")
+        imgAttrs.title = attrs.remove("imgTitle")
+        imgAttrs.each { k, v ->
+            if(v)
+                img += "${k}=\"${v.encodeAsHTML()}\" "
+        }
+        img += "/>"
+
+        writer << "<th "
+
+        // process remaining attributes
+        attrs.each { k, v ->
+            writer << "${k}=\"${v.encodeAsHTML()}\" "
+        }
+        writer << ">${link(action:action, params:linkParams) { img } }"
+        writer << "</th>"
+
+    } // sortableColumnWithImg
+
+    /**
+    * Customised version of jasperButton as found in jaser plugin.
+     * custom:jasperButtons is intended to be wrapped by g:jasperForm
+     */
+    def jasperButtons = {attrs ->
+        if(!attrs['format']){throw new Exception(message(code:"jasper.taglib.missingAttribute", args:'format'))}
+        if(!attrs['jasper']){throw new Exception(message(code:"jasper.taglib.missingAttribute", args:'jasper'))}
+        String jasper = attrs['jasper']
+        String buttonClass = attrs['class'] ?:  "jasperButton"
+        String format = attrs['format'].toUpperCase()
+        String text = attrs['text']
+        String heightAttr = attrs['height'] ? ' height="' + attrs['height'] + '"' : '' // leading space on purpose
+        String imgSrc = ''
+        String delimiter = attrs['delimiter'] ?: "|"
+        String delimiterBefore = attrs['delimiterBefore'] ?: delimiter
+        String delimiterAfter = attrs['delimiterAfter'] ?: delimiter
+
+        out << '''
+                    <script type="text/javascript">
+                        function submit_jasperForm(name, fmt) {
+                            var jasperForm = document.getElementsByName(name).item(0)
+                            jasperForm._format.value = fmt;
+                            jasperForm.submit();
+                            return false;
+                        }
+                    </script>
+                    '''
+
+        out << delimiterBefore
+
+        attrs['format'].toUpperCase().split(",").eachWithIndex { it, i ->
+            if (i > 0) out << delimiter
+            imgSrc = g.resource(plugin:"jasper", dir:'images/icons', file:"${it.trim()}.gif")
+            def fmt = it.trim()
+            out << """
+                        <a href="#" class="${buttonClass}" title="${it.trim()}" onClick="return submit_jasperForm('${jasper}', '${fmt}')">
+                        <img border="0" src="${imgSrc}"${heightAttr} /></a>
+                        """
+        }
+
+        out << delimiterAfter
+    } // jasperButtons
+
+    /**
+    * Easily create a link from a hopeful url string.
+    * If the supplied url is not considered a valid url the string is simply displayed.
+    *
+    * Fields:
+    *  url - String url to use.
+    *  body - If no body is supplied in the GSP then url.encodeAsHTML() is displayed.
+    *
+    * Example:
+    * <!--
+    * <custom:easyUrl url="${docRef.location}" />
+    * -->
+    */
+    def easyUrl = {attrs, body ->
+
+        def url = attrs.url
+
+        def html
+
+        body = body()
+        if(!body)
+            body = url.encodeAsHTML()
+
+        html = "${body}"
+
+        if(isURLValid(url)) {
+            html = """
+                        <a href="${url}">
+                            ${html}
+                        </a>
+                        """
+        }
+
+        out << html
+    }
+
+    /**
+    * Get a list of the machines assigned on a taskProcedureRevision.
+    *
+    * Fields:
+    *  taskProcedureRevision - TaskProcedureRevision to use.
+    *
+    * Example:
+    * <!--
+    * <custom:taskProcedureMachines taskProcedureRevision="${taskInstance.taskProcedureRevision}" />
+    * -->
+    */
+    def taskProcedureMachines = {attrs ->
+        def taskProcedureRevision = attrs.taskProcedureRevision
+        def machines = taskProcedureRevision.maintenanceActions.collect {it.assetSubItem.parentItem}.unique()
+        out << machines.encodeAsHTML()
+    }
+
+    /**
+    * Customised version of helpBalloon as found in help-balloon plugin.
+    * This version can be used in ajax rendered templates where the original fails.
+    *
+    * Fields added:
+    * iconId - Optional to specify the anchor elements id, by default an id is generated if iconSrc is supplied.
+    * iconSrc - Optional to specify anchor image src, if not supplied no anchor image is output by the taglib.
+    *
+    * Example:
+    * <!--
+    * <custom:helpBalloon code="entry.date.done" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}"/>
+    * or
+    * <a href="#" id="mynewanchor" onclick="return false;">this</a>
+    * <custom:helpBalloon code="entry.date.done" iconId="mynewanchor" />
+    * -->
+    */
+    def helpBalloon = {attrs, body ->
+        def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
+
+        def title = attrs["title"]
+        def content = attrs["content"]
+        def code = attrs["code"]
+        def suffix = attrs["suffix"] ?: ".help"
+        def encodeAs = attrs["encodeAs"]
+        def iconId = attrs["iconId"]
+        def iconSrc =  attrs["iconSrc"]
+
+        if (!title && code) title = g.message(code: code)
+        if (!content && code) content = g.message(code: code + suffix)
+
+        title = title ?: ""
+        content = content ?: ""
+
+        if (encodeAs) {
+            switch (encodeAs.toUpperCase()) {
+
+                case "HTML":
+                    title = title.encodeAsHTML()
+                    content = content.encodeAsHTML()
+                    break
+
+                case "XML":
+                    title = title.encodeAsXML()
+                    content = content.encodeAsXML()
+                    break
+            }
+        }
+
+        def num
+        synchronized (helpBalloonLockable) {
+            num = helpBalloonCount++;
+        }
+
+        if(iconSrc) {
+            iconId = iconId ?: "customHb$num"
+            mkp.img( id: iconId, src: iconSrc)
+        }
+
+        def javascript = """var customHb$num = new HelpBalloon({
+    title: '${title.encodeAsJavaScript()}',
+    content: '${content.encodeAsJavaScript()}'"""
+
+        if(iconId) {
+        javascript +=""",
+    icon: \$('$iconId')"""
+        }
+
+        javascript += """
+});"""
+
+        mkp.script(type: "text/javascript") {
+            yieldUnescaped(javascript)
+        }
+
+    }
+
+    /**
+    * Determine if a supplied string is considered a url or not.
+    * The scheme/protocol can be adjusted, file:// has been excluded here.
+    * A domainValidator regex is used to allow localhost domain.
+    * A Grails branched version of commons.validator is used, this should
+    * be compatible with the apache 1.4 version release.
+    * See: http://jira.codehaus.org/browse/GRAILS-1692 for more on Grails url validation.
+    */
+    private Boolean isURLValid(url) {
+
+        def schemes = ["http","https", "ftp"] as String[]
+        //def domainValidator = new RegexValidator("localhost(:(\\d{1,5}))?")
+        def domainValidator = new RegexValidator(".*(:(\\d{1,5}))?") // Any domain, incl user@host:port
+        def validator = new UrlValidator(schemes, domainValidator, UrlValidator.ALLOW_2_SLASHES)
+        return validator.isValid(url)
+
+    }
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/taglib/JsUtilTagLib.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/taglib/JsUtilTagLib.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/taglib/JsUtilTagLib.groovy	(revision 875)
@@ -0,0 +1,58 @@
+
+/**
+* JsUtil tags.
+* Javascript Utility tags.
+*/
+class JsUtilTagLib {
+    static namespace = 'jsUtil'
+
+    def js = new JsUtilService()
+
+    /**
+    * Resources.
+     * To be included in the page head tag.
+    */
+    def resources = { attrs ->
+        out << g.javascript(src: "jsUtil.js")
+    }
+
+    /**
+    * Toggle the visibility of an html element and update an image.
+    * @param toggleId The html id of the element to toggle.
+    * @param imageId The html id to apply to the image.
+    * @param openImgUrl The url to apply as the image src when toggled element is visible.
+    * @param closedImgUrl The url to apply as the image src when toggled element is hidden.
+    * @param effect The effect to apply, 'fade' uses the fade/appear effect while the default is to just toggle.
+    * @param text The text, if any, to display.
+    * @param useDiv Whether or not to use a wrapping div, default is 'true'.
+    */
+    def toggleControl = { attrs ->
+        def mkp = new groovy.xml.MarkupBuilder(out) //this line will be unnecessary in versions of Grails after version 1.2
+
+        def toggleJs
+
+        // Do we want to fade/appear or just toggle.
+        if(attrs.effect == "fade")
+            toggleJs = js.toggleWithImgAndEffect(attrs.toggleId, attrs.imageId, attrs.openImgUrl, attrs.closedImgUrl)
+        else
+            toggleJs = js.toggleWithImg(attrs.toggleId, attrs.imageId, attrs.openImgUrl, attrs.closedImgUrl)
+
+        if(attrs.useDiv == 'false') {
+            mkp.a( href: toggleJs ) {
+                    yieldUnescaped(attrs.text)
+                    img(id: attrs.imageId, src: attrs.closedImgUrl, alt: "Show")
+            } // mkp
+
+        }
+        else {
+            mkp.div() {
+                a( href: toggleJs ) {
+                    yieldUnescaped(attrs.text)
+                    img(id: attrs.imageId, src: attrs.closedImgUrl, alt: "Show")
+                }
+            } // mkp
+        }
+
+    } // hideShowControl
+
+} // end class
Index: /branches/features/grailsUpgrade/grails-app/taglib/WebAlbumTagLib.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/taglib/WebAlbumTagLib.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/taglib/WebAlbumTagLib.groovy	(revision 875)
@@ -0,0 +1,88 @@
+class WebAlbumTagLib {
+
+    static namespace = "wa"
+
+    def pictureAnchor = { attrs, body ->
+        def picture = attrs.remove('picture')
+        def size = attrs.remove('size')
+        out << "<a href=\"${createPictureLink(picture.id, size).encodeAsHTML()}\""
+        attrs.each { key, value ->
+            out << " $key=\"$value\""
+        }
+        out << '>'
+        out << body()
+        out << '</a>'
+    }
+
+    def pictureImg = { attrs ->
+        def picture = attrs.remove('picture')
+        def size = attrs.remove('size')
+        out << createPictureImage(picture, size, attrs)
+    }
+
+    def pictureLightboxAnchor = { attrs ->
+        def picture = attrs.remove('picture')
+        def size = attrs.remove('size')
+        def lightboxSize = attrs.remove('lightboxSize')
+        //def caption = picture.caption
+//         if (!caption) {
+            def caption = 'Show original'
+//         }
+        caption = caption.encodeAsHTML()
+        StringBuilder sb = new StringBuilder(40)
+        sb.append("<a href=\"${createPictureLink(picture.id, Image.Original).encodeAsHTML()}\"")
+        attrs.each { key, value ->
+            sb.append(" $key=\"$value\"")
+        }
+        sb.append('>')
+        sb.append(caption.replaceAll(/'/, '&#39;'))
+        sb.append('</a>')
+        def link = sb.toString().encodeAsHTML()
+        out << "<a href=\"${createPictureLink(picture.id, lightboxSize).encodeAsHTML()}\" rel=\"lightbox[list]\" title=\"${link}\">"
+        out << createPictureImage(picture, size, null)
+        out << '</a>'
+    }
+
+    private def createPictureImage(picture, size, attrs) {
+        Integer width = 0
+        Integer height = 0
+        switch (size) {
+            case Image.Original:
+                width = picture.width
+                height = picture.height
+                break
+            default:
+                width = Image.Widths[size]
+                height = Image.Widths[size]
+                break
+        }
+//         def caption = picture.caption
+//         if (!caption) {
+            def caption = 'Show original'
+//         }
+        def alt = attrs?.remove('alt')
+        if (!alt) {
+            alt = caption
+        }
+        alt = alt.encodeAsHTML()
+        def title = attrs?.remove('title')
+        if (!title) {
+            title = caption
+        }
+        title = title.encodeAsHTML()
+        StringBuilder sb = new StringBuilder(40)
+        sb.append("<img src=\"${createPictureLink(picture.id, size).encodeAsHTML()}\" alt=\"$alt\" title=\"$title\" width=\"$width\" height=\"$height\"")
+        if (attrs) {
+            attrs.each { key, value ->
+                sb.append(" $key=\"$value\"")
+            }
+        }
+        sb.append(' />')
+        sb.toString()
+    }
+
+    private def createPictureLink(id, size) {
+        def params = [ size: size, filename: Image.filename(id, size) ]
+        createLink(url: [ controller: 'pictureDetailed', action: 'view', id: id, params: params ])
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/utils/Imaging.groovy
===================================================================
--- /branches/features/grailsUpgrade/grails-app/utils/Imaging.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/utils/Imaging.groovy	(revision 875)
@@ -0,0 +1,149 @@
+import java.awt.AlphaComposite
+import java.awt.Color
+import java.awt.Graphics2D
+import java.awt.geom.AffineTransform
+import java.awt.geom.Rectangle2D
+import java.awt.image.AffineTransformOp
+import java.awt.image.BufferedImage
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import javax.imageio.ImageIO
+
+class Imaging {
+
+    static def createAll(InventoryItem inventoryItem, Picture picture, InputStream stream) {
+        BufferedImage original = ImageIO.read(stream)
+        picture.contentType = 'image/jpeg'
+        picture.width = original.width
+        picture.height = original.height
+        def images = [ 
+            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Original),
+            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Large),
+            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Medium),
+            new Image(inventoryItem: inventoryItem, picture: picture, size: Image.Small)
+            ]
+        ByteArrayOutputStream output = new ByteArrayOutputStream(1024 * 1024)
+        updateImages(images, original, output)
+        images
+    }
+    
+    static def updateAll(Picture picture) {
+        def operation = picture.operation
+        if (operation == Picture.NoOp) {
+            return null
+        }
+        def images = picture.images.toArray() // Image.findAllByPicture(picture, [ sort: 'size', order: 'asc' ])
+        BufferedImage original = ImageIO.read(new ByteArrayInputStream(images[0].data))
+        AffineTransform transform = new AffineTransform();
+        def op = null
+        boolean paint = false
+        Integer width = original.width
+        Integer height = original.height
+        switch (operation) {
+            case Picture.RotateClockWise90:
+                transform.rotate(Math.PI / 2.0)
+                transform.translate(0, -height)
+                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
+                width = original.height
+                height = original.width
+                paint = true
+                break
+            case Picture.RotateAntiClockWise90:
+                transform.rotate(-Math.PI / 2.0)
+                transform.translate(-width, 0)
+                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
+                width = original.height
+                height = original.width
+                paint = true
+                break
+            case Picture.Rotate180:
+                transform.rotate(Math.PI)
+                transform.translate(-width, -height)
+                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
+                break
+            case Picture.Flip: // vertical
+                transform.scale(-1.0d, 1.0d)
+                transform.translate(-width, 0)
+                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR)
+                break
+            case Picture.Flop: // horizontal
+                transform.scale(1.0d, -1.0d)
+                transform.translate(0, -height)
+                op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR)
+                break
+            default:
+                return images
+                break
+        }
+        BufferedImage modified = op.filter(original, null);
+        if (paint) {
+            BufferedImage changed = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
+            Graphics2D graphics = changed.createGraphics()
+            graphics.drawImage(modified, 0, 0, width, height, null)
+            graphics.dispose()
+            modified = changed
+            picture.width = width
+            picture.height = height
+        }
+        ByteArrayOutputStream output = new ByteArrayOutputStream(1024 * 1024)
+        updateImages(images, modified, output)
+        images
+    }
+
+    private static def updateImages(images, original, stream) {
+        updateImage(images[0], original, 'jpeg', stream)
+        def large = resizeImage(original, dimensions(Image.Large), false)
+        updateImage(images[1], large, 'png', stream)
+        updateImage(images[2], resizeImage(large, dimensions(Image.Medium), true), 'png', stream)
+        updateImage(images[3], resizeImage(large, dimensions(Image.Small), true), 'png', stream)
+    }
+
+    private static def updateImage(image, data, format, stream) {
+        image.contentType = "image/${format}"
+        image.width = data.width
+        image.height = data.height
+        stream.reset()
+        if (!ImageIO.write(data, format, stream)) {
+            throw new IOException("Can't write the image in the given format '${format}'")
+        }
+        image.data = stream.toByteArray()
+    }
+
+    private static def dimensions(size) {
+        [ Image.Widths[size], Image.Heights[size] ]
+    }    
+
+    private static def resizeImage(imageBuffer, dims, fit) {
+        Integer width = dims[0]
+        Integer height = dims[1]
+        Integer imageWidth = imageBuffer.width
+        Integer imageHeight = imageBuffer.height
+      
+        Double widthScale = (double)width / (double)imageWidth
+        Double heightScale = (double)height / (double)imageHeight
+        BufferedImage resizedImage = imageBuffer
+        if (widthScale < 1.0d || heightScale < 1.0d) {
+            Double scale = Math.min(widthScale, heightScale)
+            def transform = new AffineTransform()
+            transform.scale(scale, scale)
+            def op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR)
+            resizedImage = op.filter(imageBuffer, null)
+            imageWidth = resizedImage.width
+            imageHeight = resizedImage.height
+        }
+
+        if (fit && (imageWidth < width || imageHeight < height)) {
+            BufferedImage fittedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
+            Integer left = (width - imageWidth) / 2
+            Integer top = (height - imageHeight) / 2
+            Graphics2D graphics = fittedImage.createGraphics()
+            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f))
+            graphics.fill(new Rectangle2D.Double(0, 0, width, height))
+            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))
+            graphics.drawImage(resizedImage, left, top, imageWidth, imageHeight, null)
+            graphics.dispose()
+            return fittedImage
+        }
+        resizedImage
+    }
+}
Index: /branches/features/grailsUpgrade/grails-app/views/_about.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/_about.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/_about.gsp	(revision 875)
@@ -0,0 +1,200 @@
+<br />
+<br />
+<div class="dialog">
+    <table>
+        <tbody>
+            <tr><td>
+                ${applicationString.encodeAsHTML()} provides a powerful but simple to use
+                Maintenance and Inventory Management Solution for your Assets.
+                Also known as a computerised maintenance management system or CMMS.
+                Initially designed with an engineering department and mid-size industrial production enviroment in mind.
+                <br />
+                <br />
+                GnuMims is a world wide community project run from 
+                <a href="http://www.gnumims.org">http://www.gnumims.org</a>
+                and released under the <a href="http://www.gnu.org/licenses/agpl.html">GNU AGPL</a> open source license.
+                <br />
+                <br />
+                The GNU AGPL requires you to make the source code available to your network users.<br />
+                So how do you do this?<br />
+                Easy, if you are running an un-modified version just leave the link to www.gnumims.org 
+                on the header image intact. This will allow your users to find the community site and 
+                with it the source code. If you are running a modified version you are welcome to 
+                use our source code repository, ask us about a custom branch or your changes
+                may be included in the main trunk. If you don't want to do either of those then 
+                create a link in your modified version to your modified source, either way you are required 
+                to make the source code available to your network users. 
+            </td></tr>
+        </tbody>
+    </table>
+</div>
+<br />
+<br />
+<div class="dialog">
+    <table>
+        <tbody>
+            <tr><td>
+            GnuMims - A web application providing a Maintenance and Inventory Management Solution for your Assets.<br />
+            Copyright (C) 2008-2010 <a href="http://www.gnumims.org/trac/wiki/GnuMimsTeam">
+                                                            Gavin Kromhout
+                                                        </a><br />
+            Copyright (C) 2008-2010 <a href="http://www.gnumims.org/trac/wiki/GnuMimsTeam">
+                                                            Steven Tucker
+                                                        </a><br />
+            Copyright (C) 2008-2010 <a href="http://www.gnumims.org/trac/wiki/GnuMimsTeam">
+                                                            Raymond Smith
+                                                        </a><br />
+            <br />
+            This program is free software: you can redistribute it and/or modify<br />
+            it under the terms of the GNU Affero General Public License as published by<br />
+            the Free Software Foundation, either version 3 of the License, or<br />
+            (at your option) any later version.<br />
+            <br />
+            This program is distributed in the hope that it will be useful,<br />
+            but WITHOUT ANY WARRANTY; without even the implied warranty of<br />
+            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br />
+            GNU Affero General Public License for more details.<br />
+            <br />
+            You should have received a copy of the GNU Affero General Public License<br />
+            along with this program.  If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>
+            </td></tr>
+        </tbody>
+    </table>
+</div>
+<br />
+<br />
+<div class="dialog">
+    <table>
+        <tbody>
+            <tr class="prop">
+                <td valign="top" class="name">
+                    Silk icon set acknowledgement.<br />
+                    Many thanks for the fabulous silk icon set.
+                </td>
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">Author:</td>
+
+                <td valign="top" class="value">
+                    Mark James - <a href="http://www.famfamfam.com/lab/icons/silk/">http://www.famfamfam.com/lab/icons/silk/</a>
+                </td>
+
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">License:</td>
+
+                <td valign="top" class="value">
+                    <a href="http://creativecommons.org/licenses/by/3.0/">http://creativecommons.org/licenses/by/3.0/</a>
+                </td>
+
+            </tr>
+
+        </tbody>
+    </table>
+</div>
+<br />
+<br />
+<div class="dialog">
+    <table>
+        <tbody>
+            <tr class="prop">
+                <td valign="top" class="name">
+                    Lightbox acknowledgement.<br />
+                    Many thanks for Lightbox.<br />
+                    Used to display inventory item pictures.
+                </td>
+
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">Author:</td>
+
+                <td valign="top" class="value">
+                    Lokesh Dhakar - <a href="http://www.lokeshdhakar.com/projects/lightbox2/">http://www.lokeshdhakar.com/projects/lightbox2/</a>
+                </td>
+
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">License:</td>
+
+                <td valign="top" class="value">
+                    <a href="http://creativecommons.org/licenses/by/2.5/">http://creativecommons.org/licenses/by/2.5/</a>
+                </td>
+
+            </tr>
+
+        </tbody>
+    </table>
+</div>
+<br />
+<br />
+<div class="dialog">
+    <table>
+        <tbody>
+            <tr class="prop">
+                <td valign="top" class="name">
+                    WebAlbum acknowledgement.<br />
+                    Many thanks for the inspiration and code.<br />
+                    Used to display inventory item pictures.
+                </td>
+
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">Author:</td>
+
+                <td valign="top" class="value">
+                    John Leach - <a href="http://www.syger.it/Tutorials/GrailsWebAlbum.html">http://www.syger.it/Tutorials/GrailsWebAlbum.html</a>
+                </td>
+
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">License:</td>
+
+                <td valign="top" class="value">
+                    <a href="http://www.apache.org/licenses/LICENSE-2.0.html">http://www.apache.org/licenses/LICENSE-2.0.html</a>
+                </td>
+
+            </tr>
+
+        </tbody>
+    </table>
+</div>
+<br />
+<br />
+<div class="dialog">
+    <table>
+        <tbody>
+            <tr><td>
+                The MySQL java connector (if included) is licensed under the GNU GPL V02.<br />
+                Sun Microsystem's JDBC Driver for MySQL.<br />
+                Copyright 2003-2008 MySQL AB, 2008 Sun Microsystems.<br />
+                and can be obtained from <a href="http://dev.mysql.com/downloads/connector/j/5.0.html">http://dev.mysql.com/downloads/connector/j/5.0.html</a>
+            </td></tr>
+        </tbody>
+    </table>
+</div>
+<br />
+<br />
+<div class="dialog">
+    <table>
+        <tbody>
+            <tr>
+                <td>
+                The Grails-${grailsVersion.encodeAsHTML()} web framework and the plugins used are available under 
+                the <a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache 2.0</a>
+                license from  <a href="http://www.grails.org">http://www.grails.org</a>
+                </td>
+            </tr>
+                <tr>
+                    <td>
+                        Plugins: ${plugins}
+                    </td>
+                </tr>
+        </tbody>
+    </table>
+</div>
Index: /branches/features/grailsUpgrade/grails-app/views/addressDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/addressDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/addressDetailed/create.gsp	(revision 875)
@@ -0,0 +1,139 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Address</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Address</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${addressInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${addressInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            
+                            <g:if test="${addressInstance.supplier}">
+                                <g:hiddenField name="supplier.id" value="${addressInstance.supplier.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="supplier">Supplier:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'supplier','errors')}">
+                                        <g:link controller="supplierDetailed" action="show" id="${addressInstance.supplier.id}">
+                                            ${addressInstance.supplier.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr>
+                            </g:if>
+                            
+                            <g:if test="${addressInstance.person}">
+                                <g:hiddenField name="person.id" value="${addressInstance.person.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="person">Person:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="person" action="show" id="${addressInstance.person.id}">
+                                            ${addressInstance.person.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr> 
+                            </g:if>
+                            
+                            <g:if test="${addressInstance.site}">
+                                <g:hiddenField name="site.id" value="${addressInstance.site.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="site">Site:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="siteDetailed" action="show" id="${addressInstance.site.id}">
+                                            ${addressInstance.site.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr> 
+                            </g:if>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="addressType">Address Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'addressType','errors')}">
+                                    <g:select optionKey="id" from="${AddressType.list()}" name="addressType.id" value="${addressInstance?.addressType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="street1">Street 1:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'street1','errors')}">
+                                    <input type="text" maxlength="50" id="street1" name="street1" value="${fieldValue(bean:addressInstance,field:'street1')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="street2">Street 2:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'street2','errors')}">
+                                    <input type="text" maxlength="50" id="street2" name="street2" value="${fieldValue(bean:addressInstance,field:'street2')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="city">City:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'city','errors')}">
+                                    <input type="text" maxlength="50" id="city" name="city" value="${fieldValue(bean:addressInstance,field:'city')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="state">State:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'state','errors')}">
+                                    <input type="text" maxlength="50" id="state" name="state" value="${fieldValue(bean:addressInstance,field:'state')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="postCode">Post Code:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'postCode','errors')}">
+                                    <input type="text" maxlength="50" id="postCode" name="postCode" value="${fieldValue(bean:addressInstance,field:'postCode')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="country">Country:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'country','errors')}">
+                                    <input type="text" maxlength="50" id="country" name="country" value="${fieldValue(bean:addressInstance,field:'country')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/addressDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/addressDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/addressDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,140 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Address</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Address</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${addressInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${addressInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${addressInstance?.id}" />
+                <input type="hidden" name="version" value="${addressInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            
+                            <g:if test="${addressInstance.supplier}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="supplier">Supplier:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="supplierDetailed" action="show" id="${addressInstance.supplier.id}">
+                                            ${addressInstance.supplier.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr> 
+                            </g:if>
+                            
+                            <g:if test="${addressInstance.person}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="person">Person:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="person" action="show" id="${addressInstance.person.id}">
+                                            ${addressInstance.person.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr> 
+                            </g:if>
+                            
+                            <g:if test="${addressInstance.site}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="site">Site:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="siteDetailed" action="show" id="${addressInstance.site.id}">
+                                            ${addressInstance.site.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr> 
+                            </g:if>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="addressType">Address Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'addressType','errors')}">
+                                    <g:select optionKey="id" from="${AddressType.list()}" name="addressType.id" value="${addressInstance?.addressType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="street1">Street1:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'street1','errors')}">
+                                    <input type="text" maxlength="50" id="street1" name="street1" value="${fieldValue(bean:addressInstance,field:'street1')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="street2">Street2:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'street2','errors')}">
+                                    <input type="text" maxlength="50" id="street2" name="street2" value="${fieldValue(bean:addressInstance,field:'street2')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="city">City:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'city','errors')}">
+                                    <input type="text" maxlength="50" id="city" name="city" value="${fieldValue(bean:addressInstance,field:'city')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="state">State:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'state','errors')}">
+                                    <input type="text" maxlength="50" id="state" name="state" value="${fieldValue(bean:addressInstance,field:'state')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="postCode">Post Code:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'postCode','errors')}">
+                                    <input type="text" maxlength="50" id="postCode" name="postCode" value="${fieldValue(bean:addressInstance,field:'postCode')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="country">Country:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:addressInstance,field:'country','errors')}">
+                                    <input type="text" maxlength="50" id="country" name="country" value="${fieldValue(bean:addressInstance,field:'country')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/addressDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/addressDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/addressDetailed/list.gsp	(revision 875)
@@ -0,0 +1,80 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Address List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Address List</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="street1" title="Street1" />
+                        
+                   	        <g:sortableColumn property="street2" title="Street2" />
+                        
+                   	        <g:sortableColumn property="city" title="City" />
+                        
+                   	        <g:sortableColumn property="state" title="State" />
+                        
+                   	        <g:sortableColumn property="postCode" title="Post Code" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${addressInstanceList}" status="i" var="addressInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/addressDetailed/show/${addressInstance.id}"'>
+                                ${fieldValue(bean:addressInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/addressDetailed/show/${addressInstance.id}"'>
+                                ${fieldValue(bean:addressInstance, field:'street1')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/addressDetailed/show/${addressInstance.id}"'>
+                                ${fieldValue(bean:addressInstance, field:'street2')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/addressDetailed/show/${addressInstance.id}"'>
+                                ${fieldValue(bean:addressInstance, field:'city')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/addressDetailed/show/${addressInstance.id}"'>
+                                ${fieldValue(bean:addressInstance, field:'state')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/addressDetailed/show/${addressInstance.id}"'>
+                                ${fieldValue(bean:addressInstance, field:'postCode')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${addressInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${addressInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/addressDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/addressDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/addressDetailed/show.gsp	(revision 875)
@@ -0,0 +1,115 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Address</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Address</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:addressInstance, field:'id')}</td>
+                            
+                        </tr>
+                            
+                            <g:if test="${addressInstance.supplier}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">Supplier:</td>
+                                    
+                                    <td valign="top" class="value"><g:link controller="supplierDetailed" action="show" id="${addressInstance.supplier.id}">${addressInstance.supplier.encodeAsHTML()}</g:link></td>
+                                    
+                                </tr>
+                            </g:if>
+                            
+                            <g:if test="${addressInstance.person}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">Person:</td>
+                                    
+                                    <td valign="top" class="value"><g:link controller="person" action="show" id="${addressInstance.person.id}">${addressInstance.person.encodeAsHTML()}</g:link></td>
+                                    
+                                </tr>
+                            </g:if>
+                            
+                            <g:if test="${addressInstance.site}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">Site:</td>
+                                    
+                                    <td valign="top" class="value"><g:link controller="siteDetailed" action="show" id="${addressInstance.site.id}">${addressInstance.site.encodeAsHTML()}</g:link></td>
+                                    
+                                </tr>
+                            </g:if>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Address Type:</td>
+                            
+                            <td valign="top" class="value">${addressInstance?.addressType?.encodeAsHTML()}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Street1:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:addressInstance, field:'street1')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Street2:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:addressInstance, field:'street2')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">City:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:addressInstance, field:'city')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">State:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:addressInstance, field:'state')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Post Code:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:addressInstance, field:'postCode')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Country:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:addressInstance, field:'country')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${addressInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appConfig/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appConfig/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appConfig/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create AppConfig</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">AppConfig List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create AppConfig</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${appConfigInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${appConfigInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:appConfigInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="100" id="name" name="name" value="${fieldValue(bean:appConfigInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:appConfigInstance,field:'value','errors')}">
+                                    <textarea rows="5" cols="40" name="value">${fieldValue(bean:appConfigInstance, field:'value')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:appConfigInstance,field:'description','errors')}">
+                                    <textarea rows="5" cols="40" name="description">${fieldValue(bean:appConfigInstance, field:'description')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appConfig/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appConfig/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appConfig/edit.gsp	(revision 875)
@@ -0,0 +1,68 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit AppConfig</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">AppConfig List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New AppConfig</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit AppConfig</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${appConfigInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${appConfigInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${appConfigInstance?.id}" />
+                <input type="hidden" name="version" value="${appConfigInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:appConfigInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="100" id="name" name="name" value="${fieldValue(bean:appConfigInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:appConfigInstance,field:'value','errors')}">
+                                    <textarea rows="5" cols="40" name="value">${fieldValue(bean:appConfigInstance, field:'value')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:appConfigInstance,field:'description','errors')}">
+                                    <textarea rows="5" cols="40" name="description">${fieldValue(bean:appConfigInstance, field:'description')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appConfig/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appConfig/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appConfig/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>AppConfig List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New AppConfig</g:link></span>
+        </div>
+        <div class="body">
+            <h1>AppConfig List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="value" title="Value" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${appConfigInstanceList}" status="i" var="appConfigInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${appConfigInstance.id}">${fieldValue(bean:appConfigInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:appConfigInstance, field:'name')}</td>
+                        
+                            <td>${fieldValue(bean:appConfigInstance, field:'value')}</td>
+                        
+                            <td>${fieldValue(bean:appConfigInstance, field:'description')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${appConfigInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appConfig/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appConfig/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appConfig/show.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show AppConfig</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">AppConfig List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New AppConfig</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show AppConfig</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:appConfigInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:appConfigInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Value:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:appConfigInstance, field:'value')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:appConfigInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${appConfigInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appCore/appAdmin.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appCore/appAdmin.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appCore/appAdmin.gsp	(revision 875)
@@ -0,0 +1,95 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Admin</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Create:</label>
+                            </td>
+                            <td valign="top" class="value">
+
+                                <g:if test="${offerBaseDataCreation}">
+                                    <g:link action="createBaseData">Base</g:link> - Create the base data required for the application to function.
+                                </g:if>
+                                <g:else>
+                                    <g:if test="${baseDataCreated}">
+                                        Base data has been created.
+                                    </g:if>
+                                </g:else>
+
+                                <br />
+
+                                <g:if test="${demoDataCreationDisabled}">
+                                    Demo data creation has been disabled.
+                                </g:if>
+                                <g:else>
+                                    <g:if test="${offerDemoDataCreation}">
+                                        <g:link action="createDemoData">Demo</g:link> - Create demo data for some example sites.
+                                        <br />
+                                        <g:link action="disableDemoDataCreation">Disable</g:link> - Disable demo data creation.
+                                    </g:if>
+                                    <g:else>
+                                        <g:if test="${demoDataCreated}">
+                                            Demo data has been created.
+                                        </g:if>
+                                    </g:else>
+                                </g:else>
+
+                                <br />
+                                <br />
+
+                                <g:link action="createRecommendedAssetExtendedAttributes">Asset Extended Attributes</g:link> - Create recommended extended attributes for assets.
+                                <br />
+                                <g:link action="createRecommendedAssetSubItemExtendedAttributes">Sub Asset Extended Attributes</g:link> - Create recommended extended attributes for level 1 sub assets.
+
+                            </td>
+                        </tr>
+
+                        <g:if env="development">
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Bulk Test:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:link action="createBulkTestData">All Types</g:link> - Create a large volume of test data.
+                                    <br />
+                                    <g:link action="createBulkInventoryTestData">Inventory</g:link> - Create a large volume of inventory test data.
+                                </td>
+                            </tr>
+                        </g:if>
+
+                    </tbody>
+                </table>
+            </div> <!--End dialog-->
+            <br />
+            <br />
+            <div class="errors">
+                Warning!<br />
+                The pages bellow this line are for use by the application admin only and NOT for daily use.<br />
+                They allow direct administration of the back-end data, uncontrolled cascade deletion and updates may occur.<br />
+                The manager authorisation and pages should be used for normal daily use.<br />
+            </div>
+            <br/>
+            <div class="dialog">
+                <ul>
+                <g:each var="c" in="${grailsApplication.controllerClasses.sort { p1, p2 -> p1.fullName.compareToIgnoreCase(p2.fullName) } }">
+                        <li class="controller"><g:link controller="${c.logicalPropertyName}">${c.logicalPropertyName[0].toUpperCase() + c.logicalPropertyName[1..-1]}</g:link></li>
+                </g:each>
+                </ul>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appCore/appLog.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appCore/appLog.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appCore/appLog.gsp	(revision 875)
@@ -0,0 +1,20 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Application Log</title>
+        <nav:resources override="true"/>
+    </head>
+    <body onload="textAreaScrollBottom('log');">
+        <div class="nav">
+            <h1>Application Log</h1>
+        </div>
+        <div class="body">
+
+            <textarea rows="30" cols="90" id="log" name="log" readonly="yes">
+                ${log.encodeAsHTML()}
+            </textarea>
+
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appCore/changePassword.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appCore/changePassword.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appCore/changePassword.gsp	(revision 875)
@@ -0,0 +1,52 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Change Password</title>
+    <nav:resources override="true"/>
+</head>
+
+<body onload="document.changePasswordForm.pass.focus();">
+    <div class="nav">
+        <nav:renderSubItems group="nav"/>
+    </div>
+
+    <div class="body">
+        <g:if test="${flash.message}">
+        <div class="message">${flash.message}</div>
+        </g:if>
+        <g:hasErrors bean="${personInstance}">
+        <div class="errors">
+            <g:renderErrors bean="${personInstance}" as="list" />
+        </div>
+        </g:hasErrors>
+
+            <g:form name="changePasswordForm" id="changePasswordForm">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name"><label for="pass">Password:</label></td>
+                            <td valign="top" class="value ${hasErrors(bean:personInstance,field:'pass','errors')}">
+                                <input type="password" id="pass" name="pass" />
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name"><label for="confirmPass">Confirm password:</label></td>
+                            <td valign="top" class="value">
+                                <input type="password" id="confirmPass" name="confirmPass" />
+                            </td>
+                        </tr>
+
+                    </tbody>
+                </table>
+            </div>
+
+            <div class="buttons">
+                <span class="button"><g:actionSubmit class="save" value="Change Password" action="changePassword"/></span>
+            </div>
+        </g:form>
+
+    </div>
+
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/appCore/changeSessionTimeout.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appCore/changeSessionTimeout.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appCore/changeSessionTimeout.gsp	(revision 875)
@@ -0,0 +1,49 @@
+<head>
+	<meta name="layout" content="main" />
+	<title>Change Session Timeout</title>
+    <nav:resources override="true"/>
+</head>
+
+<body onload="document.changeSessionTimeoutForm.sessionTimeout.focus();">        
+    <div class="nav">
+        <nav:renderSubItems group="nav"/>
+    </div>
+
+	<div class="body">
+		<g:if test="${flash.message}">
+		<div class="message">${flash.message}</div>
+		</g:if>
+		<g:hasErrors bean="${personInstance}">
+		<div class="errors">
+			<g:renderErrors bean="${personInstance}" as="list" />
+		</div>
+		</g:hasErrors>
+
+		<g:form name="changeSessionTimeoutForm" id="changeSessionTimeout">
+			<div class="dialog">
+				<table>
+				<tbody>
+
+					<tr class="prop">
+						<td valign="top" class="name">
+                            <label for="sessionTimeout">Session timeout:</label>
+                        </td>
+
+                        <td valign="top" class="value">
+						<input valign="top" class="duration ${hasErrors(bean:personInstance,field:'sessionTimeout','errors')}"
+                             type="text" id="sessionTimeout" name="sessionTimeout" value="${fieldValue(bean:personInstance,field:'sessionTimeout')}"/>
+                            seconds
+					</tr>
+
+				</tbody>
+				</table>
+			</div>
+
+			<div class="buttons">
+				<span class="button"><g:actionSubmit class="save" value="Save" action="changeSessionTimeout"/></span>
+			</div>
+		</g:form>
+
+	</div>
+
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/appCore/manager.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appCore/manager.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appCore/manager.gsp	(revision 875)
@@ -0,0 +1,93 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Manager</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+                <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Manage:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <a href="${createLink(controller:'person', action:'list')}">Application users</a>
+                                <br />
+                                <a href="${createLink(controller:'personGroupDetailed', action:'list')}">Assigned Groups</a>
+                                <br />
+                                <a href="${createLink(controller:'costCodeDetailed', action:'list')}">Cost Codes</a>
+                                <br />
+                                <a href="${createLink(controller:'departmentDetailed', action:'list')}">Departments</a>
+                                <br />
+                                <a href="${createLink(controller:'inventoryLocationDetailed', action:'list')}">Inventory Locations</a>
+                                <br />
+                                <a href="${createLink(controller:'inventoryGroupDetailed', action:'list')}">Inventory Groups</a>
+                                <br />
+                                <a href="${createLink(controller:'inventoryStoreDetailed', action:'list')}">Inventory Stores</a>
+                                <br />
+                                <a href="${createLink(controller:'maintenancePolicyDetailed', action:'list')}">Maintenance Policies</a>
+                                <br />
+                                <a href="${createLink(controller:'purchasingGroupDetailed', action:'list')}">Purchasing Groups</a>
+                                <br />
+                                <a href="${createLink(controller:'productionReferenceDetailed', action:'list')}">Production Reference</a>
+                                <br />
+                                <a href="${createLink(controller:'supplierDetailed', action:'list')}">Suppliers</a>
+                                <br />
+                                <a href="${createLink(controller:'taskGroupDetailed', action:'list')}">Task Groups</a>
+                                <br />
+                                <a href="${createLink(controller:'taskProcedureDetailed', action:'list')}">Task Procedures</a>
+                                <br />
+                                <a href="${createLink(controller:'taskRecurringScheduleDetailed', action:'list')}">Task Recurring Schedules</a>
+                                <br />
+                                <a href="${createLink(controller:'unitOfMeasureDetailed', action:'list')}">Unit Of Measure</a>
+                                <br />
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Application:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <g:link action="appLog">
+                                    View
+                                </g:link> - The application log file.
+                                <br />
+                                <g:link action="rebuildTextSearchIndex">
+                                    Rebuild
+                                </g:link> - Rebuild the text search index.
+                                <br />
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Entity Relationship Diagram:</label>
+                            </td>
+                            <td valign="top" class="value">
+
+                                <a href="${createLink(controller:'classDiagram', action:'model', params:[outputFormat: 'pdf', skin: 'classicSpaced', showMethods: 'false', autoUpdate: 'false'])}">PDF</a>
+                                <br />
+                                <a href="${createLink(controller:'classDiagram', action:'legend', target:'_blank')}">Legend</a>
+                                <br />
+                                <a href="${createLink(controller:'classDiagram', action:'show')}">Interactive.</a>
+                            </td>
+                        </tr>
+
+                    </tbody>
+                </table>
+            </div> <!--End dialog-->
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/appCore/start.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/appCore/start.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/appCore/start.gsp	(revision 875)
@@ -0,0 +1,278 @@
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+    <meta name="layout" content="main" />
+    <title>Start</title>
+    <nav:resources override="true"/>
+    <resource:tabView skin="tabviewCustom" />
+    <resource:dateChooser />
+</head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${appCore}">
+                <div class="errors">
+                    <g:renderErrors bean="${appCore}" as="list" />
+                </div>
+            </g:hasErrors>
+
+            <richui:tabView id="tabView">
+
+                <richui:tabLabels>
+                    <richui:tabLabel selected="${showTab.quickLinks}" title="Quick Links" />
+                    <richui:tabLabel selected="${showTab.reports}" title="Reports" />
+                    <richui:tabLabel selected="${showTab.Options}" title="Options" />
+                    <richui:tabLabel selected="${showTab.about}" title="About" />
+                </richui:tabLabels>
+
+                <richui:tabContents>
+
+<!-- Tasks tab -->
+                    <richui:tabContent>
+                        <br />
+                        <br />
+                        <div class="dialog">
+                            <table>
+                                <tbody>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="name">
+                                            <label>My Tasks:</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                            <g:link controller="taskDetailed"
+                                                            action="search"
+                                                            params="[quickSearch: 'myTodays']">
+                                                            Today
+                                            </g:link>
+                                        </td>
+                                    </tr>
+            
+                                    <tr class="prop">
+                                        <td valign="top" class="name">
+                                            <label>All Tasks:</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                            <g:link controller="taskDetailed" 
+                                                            action="search"
+                                                            params="[quickSearch: 'pastWeek']">
+                                                            Past Week
+                                            </g:link>
+                                            <br />
+                                            <g:link controller="taskDetailed" 
+                                                            action="searchCalendar"
+                                                            params="[quickSearch: 'searchPlannersRange']">
+                                                            Calendar
+                                            </g:link>
+                                        </td>
+                                    </tr>
+
+<!--                                    More Quick Links:
+                                    Open Tasks
+                                    Closed Tasks
+                                    Tasks I lead.
+                                    Week calender
+                                    Recent
+                                    Today's Entries
+                                    My Entries.
+                                    Date ranges-->
+
+                                </tbody>
+                            </table>
+                        </div> <!--End dialog-->
+                    </richui:tabContent>
+<!-- End Tasks tab -->
+
+<!-- Reports tab -->
+                    <richui:tabContent>
+                        <br />
+                        <br />
+                        <div class="dialog">
+                            <table>
+                                <tbody>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="name">
+                                            <label>Frequently Used:</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                            <g:jasperReport controller="report"
+                                                                            action="reactiveRatio"
+                                                                            jasper="reactiveRatio"
+                                                                            name="Reactive Ratio"
+                                                                            format="PDF, XLS">
+                                                <richui:dateChooser name="startDate" id="reactiveRatio_startDate" format="dd-MM-yyyy" value="${new Date()-7}" />
+                                                to
+                                                <richui:dateChooser name="endDate" id="reactiveRatio_endDate" format="dd-MM-yyyy" value="${new Date()}" />
+                                            </g:jasperReport>
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="immediateCallouts"
+                                                                            jasper="immediateCallouts"
+                                                                            name="Immediate Callouts"
+                                                                            format="PDF, XLS">
+                                                <richui:dateChooser name="startDate" id="immediateCallouts_startDate" format="dd-MM-yyyy" value="${new Date()-7}" />
+                                                to
+                                                <richui:dateChooser name="endDate" id="immediateCallouts_endDate" format="dd-MM-yyyy" value="${new Date()}" />
+                                            </g:jasperReport>
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="stockTakeOverview"
+                                                                            jasper="stockTakeOverview"
+                                                                            name="Stock Take (Overview)"
+                                                                            format="PDF, XLS">
+                                                <g:helpBalloon class="helpballoon" code="report.stock.take.overview" />
+                                            </g:jasperReport>
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="stockTakeByLocation"
+                                                                            jasper="stockTakeByLocation"
+                                                                            name="Stock Take (By Location)"
+                                                                            format="PDF, XLS">
+                                                <g:textField name="locationString" value="e.g: A1%, C55" />
+                                                <g:helpBalloon class="helpballoon" code="report.stock.take.by.location" />
+                                            </g:jasperReport>
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="templatePortrait"
+                                                                            jasper="templatePortrait"
+                                                                            name="Template (Portrait)"
+                                                                            format="PDF, XLS">
+                                                <g:link controller="report" action="downloadTemplate" params="[fileName: 'templatePortrait.jrxml']">
+                                                    Download
+                                                </g:link>
+                                            </g:jasperReport>
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="templateLandscape"
+                                                                            jasper="templateLandscape"
+                                                                            name="Template (Landscape)"
+                                                                            format="PDF, XLS">
+                                                <g:link controller="report" action="downloadTemplate" params="[fileName: 'templateLandscape.jrxml']">
+                                                    Download
+                                                </g:link>
+                                            </g:jasperReport>
+                                            <br />
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="name">
+                                            <label>Assets:</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                            <g:link controller="report" action="equipmentRegisterOhsGsp">
+                                                Equipment Register (OH&amp;S)
+                                            </g:link>
+                                            <br />
+                                            <br />
+                                            <g:link controller="report" action="regulatoryRequirementsGsp">
+                                                <img  src="${resource(dir:'images/skin',file:'script_lightning.png')}" alt="Regulatory Requirement" title="Regulatory Requirement" />
+                                                Regulatory Requirements
+                                            </g:link>
+                                            <br />
+                                            <br />
+                                            <g:link controller="report" action="mandatoryRequirementsGsp">
+                                                <img  src="${resource(dir:'images/skin',file:'script.png')}" alt="Mandatory Requirement" title="Mandatory Requirement" />
+                                                Mandatory Requirements
+                                            </g:link>
+                                            <br />
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="equipmentRegisterFinancial"
+                                                                            jasper="equipmentRegisterFinancial"
+                                                                            name="Equipment Register (Financial)"
+                                                                            format="PDF, XLS">
+                                                <g:select optionKey="id"
+                                                                    from="${sections}"
+                                                                    name="section.id">
+                                                </g:select>
+                                            </g:jasperReport>
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="assetRegister"
+                                                                            jasper="assetRegister"
+                                                                            name="Asset Register"
+                                                                            format="PDF, XLS">
+                                                <g:select optionKey="id"
+                                                                    from="${sections}"
+                                                                    name="section.id">
+                                                </g:select>
+                                            </g:jasperReport>
+                                            <br />
+                                            <g:jasperReport controller="report"
+                                                                            action="assetDetail"
+                                                                            jasper="assetDetail"
+                                                                            name="Asset Detail"
+                                                                            format="PDF, XLS">
+                                                <g:select optionKey="id"
+                                                                    from="${sections}"
+                                                                    name="section.id"
+                                                                    noSelection="['all':/${g.message(code:'default.all.select.text')}/]">
+                                                </g:select>
+                                            </g:jasperReport>
+                                            <br />
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="name">
+                                            <label>Inventory:</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                                <g:link controller="report" action="inventoryValueOverviewGsp">
+                                                    Total Value (Overview)
+                                                </g:link>
+                                                <br />
+                                                <br />
+                                                <g:link controller="report" action="inventoryValueDetailedGsp">
+                                                    Detailed Value
+                                                </g:link>
+                                        </td>
+                                    </tr>
+
+                                </tbody>
+                            </table>
+                        </div> <!--End dialog-->
+                    </richui:tabContent>
+<!-- End Reports tab  -->
+
+<!-- Options tab -->
+                    <richui:tabContent>
+                        <br />
+                        <br />
+                        <div class="dialog">
+                            <table>
+                                <tbody>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="name">
+                                            <label>Change:</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                            <a href="${createLink(action:'changePassword')}"> Password</a>
+                                            <br />
+                                            <a href="${createLink(action:'changeSessionTimeout')}">Session Timeout</a>
+                                        </td>
+                                    </tr>
+
+                                </tbody>
+                            </table>
+                        </div> <!--End dialog-->
+                    </richui:tabContent>
+<!-- End Options tab -->
+
+<!-- About tab -->
+                    <richui:tabContent>
+                        <g:render template="/about" />
+                    </richui:tabContent>
+<!-- End About tab -->
+
+                </richui:tabContents>
+            </richui:tabView>
+
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetDetailed/copy.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetDetailed/copy.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetDetailed/copy.gsp	(revision 875)
@@ -0,0 +1,107 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Asset Copy</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Asset Copy</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <g:hiddenField name="assetToCopy.id" value="${assetToCopy.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Copying:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    ${assetToCopy.encodeAsHTML()}
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="copyMethod">Sub Items:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <p>
+                                        <input type="radio" name="copyMethod" value="link" />
+                                        Link
+                                        <g:helpBalloon class="helpballoon" code="asset.copy.method" />
+                                    </p>
+                                    <p>
+                                        <input type="radio" name="copyMethod" value="copy" />
+                                        Copy
+                                    </p>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:assetInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:assetInstance,field:'description')}"/>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:assetInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${assetInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="section">Section:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'section','errors')}">
+                                    <g:select optionKey="id" from="${Section.list()}" name="section.id" value="${assetInstance?.section?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Create" action="saveCopy"/></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetDetailed/create.gsp	(revision 875)
@@ -0,0 +1,80 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Asset</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:assetInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:assetInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:assetInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${assetInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="section">Section:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'section','errors')}">
+                                    <g:select optionKey="id" from="${Section.list()}" name="section.id" value="${assetInstance?.section?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,202 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Asset</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${assetInstance?.id}" />
+                <input type="hidden" name="version" value="${assetInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Asset</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:assetInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="100" id="description" name="description" value="${fieldValue(bean:assetInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:assetInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${assetInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="section">Section:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'section','errors')}">
+                                    <g:select optionKey="id" from="${Section.list()}" name="section.id" value="${assetInstance?.section?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">Extended Attributes</td>
+                                <td  valign="top" style="text-align:left;" class="value">
+                                </td>
+                            </tr>
+                            
+                            <g:each var="a" in="${assetInstance.assetExtendedAttributes.sort { p1, p2 -> p1.extendedAttributeType.name.compareToIgnoreCase(p2.extendedAttributeType.name) }}">
+                                <tr class="prop">
+                                    <td valign="top" class="groupName">
+                                        ${a.extendedAttributeType.name.encodeAsHTML()}:
+                                    </td>
+                                    
+                                    <td  valign="top" style="text-align:left;" class="value">
+                                        <g:link controller="assetExtendedAttributeDetailed" action="edit" id="${a.id}">
+                                            ${a.value.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                
+                                </tr>
+                            </g:each>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name"></td>
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <g:link controller="assetExtendedAttributeDetailed" params="['asset.id':assetInstance?.id]" action="create">+Add Extended Attribute</g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="assetSubItems">Asset Tree</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'assetSubItems','errors')}">
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    Level 1 sub items:
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetInstance,field:'assetSubItems','errors')}">
+                                    <custom:checkBoxList name="assetSubItems"
+                                                                    from="${possibleAssetSubItems}"
+                                                                    value="${assetInstance?.assetSubItems.collect{it.id}}"
+                                                                    optionKey="id"
+                                                                    sortBy="name"
+                                                                    linkController="assetSubItemDetailed"
+                                                                    linkAction="show"/>
+
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">Life Plan</td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                </td>
+
+                            </tr>
+                            
+                            <g:each var="t" in="${parentPMs}">
+                                <tr class="prop">
+                                    <td valign="top" class="name"></td>
+                                    
+                                    <td  valign="top" style="text-align:left;" class="value">
+                                        <g:link controller="taskDetailed" action="show" id="${t.id}">
+                                            Task #${t.id}
+                                        </g:link>
+                                        <g:if test="${t.approved}" >
+                                            <img  src="${resource(dir:'images/skin',file:'cog.png')}" alt="Approved" title="Approved" />
+                                        </g:if>
+                                        <g:if test="${t.taskRecurringSchedule?.enabled}" >
+                                            <img  src="${resource(dir:'images/skin',file:'arrow_refresh.png')}" alt="Recurrence Enabled" title="Recurrence Enabled" />
+                                        </g:if>
+                                        <g:if test="${t.taskStatus.id == 2}" >
+                                            <img  src="${resource(dir:'images/skin',file:'arrow_right.png')}" alt="In Progress" title="In Progress" />
+                                        </g:if>
+                                        <g:if test="${t.attentionFlag}" >
+                                            <img  src="${resource(dir:'images/skin',file:'flag_red.png')}" alt="Attention Flag" title="Attention Flag" />
+                                        </g:if>
+                                        <g:if test="${t.taskStatus.id == 3}" >
+                                            <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Complete" title="Complete" />
+                                        </g:if>
+                                        <br />
+                                        ${fieldValue(bean:t, field:'description')}
+                                        <br />
+                                        <g:if test="${t.safetyRequirement}" >
+                                            <img  src="${resource(dir:'images/skin',file:'lightning.png')}" alt="Safety Requirement" title="Safety Requirement" />
+                                            Safety
+                                        </g:if>
+                                        <g:if test="${t.regulatoryRequirement}" >
+                                            <img  src="${resource(dir:'images/skin',file:'script_lightning.png')}" alt="Regulatory Requirement" title="Regulatory Requirement" />
+                                            Regulatory
+                                        </g:if>
+                                        <g:if test="${t.mandatoryRequirement}" >
+                                            <img  src="${resource(dir:'images/skin',file:'script.png')}" alt="Mandatory Requirement" title="Mandatory Requirement" />
+                                            Mandatory
+                                        </g:if>
+                                    </td>
+                                    
+                                </tr>
+                            </g:each>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name"></td>
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <g:link controller="taskDetailed" params="['primaryAsset.id':assetInstance?.id, 'taskType.id':6]" action="create">+Add ParentPM</g:link>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetDetailed/importAssetTree.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetDetailed/importAssetTree.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetDetailed/importAssetTree.gsp	(revision 875)
@@ -0,0 +1,35 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Import Asset Tree</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Import Asset Tree</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:uploadForm action="importAssetTreeSave" onsubmit="return Lightbox.loading();">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="file">File:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input type="file" id="file" name="file" size="40"/>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:uploadForm>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetDetailed/search.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetDetailed/search.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetDetailed/search.gsp	(revision 875)
@@ -0,0 +1,165 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Asset Search</title>
+        <nav:resources override="true"/>
+        <filterpane:includes />
+        <export:resource />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <filterpane:currentCriteria domainBean="Asset"
+                                    action="search"
+                                    dateFormat="EEE, dd-MMM-yyyy"
+                                    removeImgDir="images" 
+                                    removeImgFile="bullet_delete.png"
+                                    title="Search"/>
+
+            <div class="paginateButtons">
+                Results: ${assetInstanceList.size()} / ${assetInstanceTotal}
+                <span class="searchButtons">
+                    <filterpane:filterButton text="Search" appliedText="Change Search" />
+                </span>
+            </div>
+
+            <jsUtil:toggleControl toggleId="options"
+                                                    imageId="optionsImg"
+                                                    closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                    openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                    text="${g.message(code: 'default.options.text')}"
+                                                    />
+
+            <div id="options" style="display:none;">
+                <g:form method="post" action="setSearchParamsMax" >
+                    <g:hiddenField name="params" value="${filterParams}" />
+                    <div class="dialog">
+                        <table>
+                            <tbody>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Results per page:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <input type="text" maxlength="4" id="description" name="newMax" value="${params.max}"/>
+
+                                        <span class="buttons">
+                                            <g:actionSubmit action="setSearchParamsMax" class="go" value="Update" />
+                                        </span>
+                                    </td>
+                                </tr>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Asset Tree:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link action="exportAssetTree">
+                                            Export
+                                        </g:link>
+                                        /
+                                        <g:link action="exportAssetTreeTemplate">
+                                            Template
+                                        </g:link>
+                                        /
+                                        <g:link action="importAssetTree">
+                                            Import
+                                        </g:link>
+                                    </td>
+                                </tr>
+
+                            </tbody>
+                        </table>
+                    </div>
+                </g:form>
+                <export:formats  params="${filterParams}" formats="['csv', 'excel', 'pdf', 'rtf']"/>
+            </div>
+
+            <br />
+
+            <g:if test="${assetInstanceList.size() > 10}">
+                <g:if test="${assetInstanceTotal > assetInstanceList.size()}">
+                    <div class="paginateButtons">
+                        <g:paginate action="search" total="${assetInstanceTotal}" params="${filterParams}" />
+                    </div>
+                </g:if>
+            </g:if>
+
+            <g:if test="${assetInstanceList.size() > 0}">
+                <div class="list">
+                    <table>
+                        <thead>
+                            <tr>
+                            
+                                <g:sortableColumn property="id" title="Id" params="${filterParams}" />
+
+                                <g:sortableColumn property="name" title="Name" params="${filterParams}" />
+                            
+                                <g:sortableColumn property="description" title="Description" params="${filterParams}" />
+
+                                <g:sortableColumn property="isActive" title="Is Active" params="${filterParams}" />
+                            
+                                <g:sortableColumn property="section" title="Section" params="${filterParams}" />
+
+                                <th></th>
+                            
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <g:each in="${assetInstanceList}" status="i" var="assetInstance">
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/assetDetailed/show/${assetInstance.id}"'>
+                                    ${fieldValue(bean:assetInstance, field:'id')}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/assetDetailed/show/${assetInstance.id}"'>
+                                    ${fieldValue(bean:assetInstance, field:'name')}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/assetDetailed/show/${assetInstance.id}"'>
+                                    ${fieldValue(bean:assetInstance, field:'description')}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/assetDetailed/show/${assetInstance.id}"'>
+                                    ${fieldValue(bean:assetInstance, field:'isActive')}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/assetDetailed/show/${assetInstance.id}"'>
+                                    ${fieldValue(bean:assetInstance, field:'section')}
+                                </td>
+
+                                <td class="notClickable">
+                                    <g:link action="show" id="${assetInstance.id}">
+                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                    </g:link>
+                                </td>
+                            
+                            </tr>
+                        </g:each>
+                        </tbody>
+                    </table>
+                </div>
+            </g:if>
+            <div class="paginateButtons">
+                <g:paginate action="search" total="${assetInstanceTotal}" params="${filterParams}" />
+            </div>
+
+            <filterpane:filterPane domainBean="Asset"
+                                    title="Search"
+                                    action="search"
+                                    class="overlayPane"
+                                    excludeProperties=""
+                                    associatedProperties="section.name"
+                                    filterPropertyValues="${['section.name':[values:Section.list()] ]}" />
+        </div> <!-- end body div -->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetDetailed/show.gsp	(revision 875)
@@ -0,0 +1,178 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Asset</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="groupHeader">
+                                <label for="name">Asset</label>
+                            </td>
+                            <td valign="top" class="value">
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Id:</td>
+
+                            <td valign="top" class="value">${fieldValue(bean:assetInstance, field:'id')}</td>
+
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Name:</td>
+
+                            <td  valign="top" style="text-align:left;" class="value">
+                                ${assetInstance.name.encodeAsHTML()}
+                            </td>
+
+                        </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">Description:</td>
+                                
+                                <td valign="top" class="value">${fieldValue(bean:assetInstance, field:'description')}</td>
+                                
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">Comment:</td>
+                                
+                                <td valign="top" class="value">${fieldValue(bean:assetInstance, field:'comment')}</td>
+                                
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">Is Active:</td>
+                                
+                                <td valign="top" class="value">${fieldValue(bean:assetInstance, field:'isActive')}</td>
+                                
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">Section:</td>
+                                
+                                <td valign="top" class="value"><g:link controller="sectionDetailed" action="show" id="${assetInstance?.section?.id}">${assetInstance?.section?.encodeAsHTML()}</g:link></td>
+                                
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">Extended Attributes</td>
+                                
+                                <td  valign="top" style="text-align:left;" class="value">
+                                </td>
+                                
+                            </tr>
+                        
+                            <g:each var="a" in="${assetInstance.assetExtendedAttributes.sort { p1, p2 -> p1.extendedAttributeType.name.compareToIgnoreCase(p2.extendedAttributeType.name) }}">
+                                <tr class="prop">
+                                    <td valign="top" class="groupName">
+                                        ${a.extendedAttributeType.name.encodeAsHTML()}:
+                                    </td>
+                                    
+                                    <td  valign="top" style="text-align:left;" class="value">
+                                        <g:link controller="assetExtendedAttributeDetailed" action="edit" id="${a.id}">
+                                            ${a.value.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                
+                                </tr>
+                            </g:each>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="assetSubItems">Asset Tree</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:render template="/shared/assetTree" />
+                                </td>
+                            </tr> 
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">Life Plan</td>
+                                
+                                <td  valign="top" style="text-align:left;" class="value">
+                                </td>
+                                
+                            </tr>
+
+                            <g:each var="t" in="${parentPMs}">
+                                <tr class="prop">
+                                    <td valign="top" class="name"></td>
+                                    
+                                    <td  valign="top" style="text-align:left;" class="value">
+                                        <g:link controller="taskDetailed" action="show" id="${t.id}">
+                                            Task #${t.id}
+                                        </g:link>
+                                        <g:if test="${t.approved}" >
+                                            <img  src="${resource(dir:'images/skin',file:'cog.png')}" alt="Approved" title="Approved" />
+                                        </g:if>
+                                        <g:if test="${t.taskRecurringSchedule?.enabled}" >
+                                            <img  src="${resource(dir:'images/skin',file:'arrow_refresh.png')}" alt="Recurrence Enabled" title="Recurrence Enabled" />
+                                        </g:if>
+                                        <g:if test="${t.taskStatus.id == 2}" >
+                                            <img  src="${resource(dir:'images/skin',file:'arrow_right.png')}" alt="In Progress" title="In Progress" />
+                                        </g:if>
+                                        <g:if test="${t.attentionFlag}" >
+                                            <img  src="${resource(dir:'images/skin',file:'flag_red.png')}" alt="Attention Flag" title="Attention Flag" />
+                                        </g:if>
+                                        <g:if test="${t.taskStatus.id == 3}" >
+                                            <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Complete" title="Complete" />
+                                        </g:if>
+                                        <br />
+                                        ${fieldValue(bean:t, field:'description')}
+                                        <br />
+                                        <g:if test="${t.taskProcedureRevision?.maintenanceActions}" >
+                                            <custom:taskProcedureMachines taskProcedureRevision="${t.taskProcedureRevision}" />
+                                            <br />
+                                        </g:if>
+                                        <g:if test="${t.safetyRequirement}" >
+                                            <img  src="${resource(dir:'images/skin',file:'lightning.png')}" alt="Safety Requirement" title="Safety Requirement" />
+                                            Safety
+                                        </g:if>
+                                        <g:if test="${t.regulatoryRequirement}" >
+                                            <img  src="${resource(dir:'images/skin',file:'script_lightning.png')}" alt="Regulatory Requirement" title="Regulatory Requirement" />
+                                            Regulatory
+                                        </g:if>
+                                        <g:if test="${t.mandatoryRequirement}" >
+                                            <img  src="${resource(dir:'images/skin',file:'script.png')}" alt="Mandatory Requirement" title="Mandatory Requirement" />
+                                            Mandatory
+                                        </g:if>
+                                    </td>
+                                    
+                                </tr>
+                            </g:each>
+                        
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${assetInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,60 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create AssetExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="asset">Asset:</label>
+                                </td>
+
+                                <td valign="top" class="value">
+                                    <g:link controller="assetDetailed" action="show" id="${assetExtendedAttributeInstance?.asset?.id}">
+                                        <g:hiddenField name="asset.id" value="${assetExtendedAttributeInstance?.asset.id}" />
+                                        ${assetExtendedAttributeInstance?.asset?.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <g:select optionKey="id"
+                                                        from="${ExtendedAttributeType.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="extendedAttributeType.id"
+                                                        value="${assetExtendedAttributeInstance?.extendedAttributeType?.id}" >
+                                    </g:select>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:assetExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,74 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit AssetExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${assetExtendedAttributeInstance?.id}" />
+                <input type="hidden" name="version" value="${assetExtendedAttributeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:assetExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${assetExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="asset">Asset:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetExtendedAttributeInstance,field:'asset','errors')}">
+                                    <g:select optionKey="id" from="${Asset.list()}" name="asset.id" value="${assetExtendedAttributeInstance?.asset?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${assetExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetExtendedAttributeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,67 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show AssetExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetExtendedAttributeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Value:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetExtendedAttributeInstance, field:'value')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetExtendedAttributeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Asset:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="assetDetailed" action="show" id="${assetExtendedAttributeInstance?.asset?.id}">${assetExtendedAttributeInstance?.asset?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Extended Attribute Type:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="extendedAttributeTypeDetailed" action="show" id="${assetExtendedAttributeInstance?.extendedAttributeType?.id}">${assetExtendedAttributeInstance?.extendedAttributeType?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${assetExtendedAttributeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/create.gsp	(revision 875)
@@ -0,0 +1,86 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create AssetSubItem</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetSubItemInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetSubItemInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <g:if test="${assetSubItemInstance?.parentItem}" >
+                                <g:hiddenField name="parentItem.id" value="${assetSubItemInstance.parentItem.id}" />
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="parentItem">Parent Item:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        ${assetSubItemInstance.parentItem.encodeAsHTML()}
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <g:if test="${assetInstance}" >
+                                <g:hiddenField name="asset.id" value="${assetInstance.id}" />
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="asset">Link with Asset:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        ${assetInstance.encodeAsHTML()}
+                                    </td>
+                                </tr>
+                            </g:if>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:assetSubItemInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:assetSubItemInstance,field:'description')}"/>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:assetSubItemInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,201 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit AssetSubItem</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetSubItemInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetSubItemInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${assetSubItemInstance?.id}" />
+                <input type="hidden" name="version" value="${assetSubItemInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Asset Sub Item</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:assetSubItemInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:assetSubItemInstance,field:'description')}"/>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:assetSubItemInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${assetSubItemInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">Extended Attributes</td>
+                                <td  valign="top" style="text-align:left;" class="value">
+                                </td>
+                            </tr>
+                            
+                            <g:each var="a" in="${assetSubItemInstance.assetSubItemExtendedAttributes.sort { p1, p2 -> p1.extendedAttributeType.name.compareToIgnoreCase(p2.extendedAttributeType.name) }}">
+                                <tr class="prop">
+                                    <td valign="top" class="groupName">
+                                        ${a.extendedAttributeType.name.encodeAsHTML()}:
+                                    </td>
+
+                                    <td  valign="top" style="text-align:left;" class="value">
+                                        <g:link controller="assetSubItemExtendedAttributeDetailed" action="edit" id="${a.id}">
+                                            ${a.value.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+
+                                </tr>
+                            </g:each>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                </td>
+                                <td valign="top" style="text-align:left;" class="value">
+                                    <g:link controller="assetSubItemExtendedAttributeDetailed" params="['assetSubItem.id':assetSubItemInstance?.id]" action="create">+Add Extended Attribute</g:link>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Asset Tree</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">Assets:</td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <g:if test="${assetSubItemInstance.parentItem}" >
+                                        N/A (Assigned to parent item)
+                                    </g:if>
+                                    <g:else>
+                                        <g:if test="${assetSubItemInstance.assets}">
+                                            <ul>
+                                            <g:each var="a" in="${ assetSubItemInstance.assets.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                                                <li><g:link controller="assetDetailed" action="show" id="${a.id}">${a?.encodeAsHTML()}</g:link></li>
+                                            </g:each>
+                                            </ul>
+                                        </g:if>
+                                        <g:else>
+                                            May be assigned via asset edit view.
+                                        </g:else>
+                                    </g:else>
+                                </td>
+
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="parentItem">Parent Item:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'parentItem','errors')}">
+                                    <g:if test="${assetSubItemInstance.assets}">
+                                        Level 1 sub item (Assigned directly to assets)
+                                    </g:if>
+                                    <g:else>
+                                        <g:select optionKey="id" from="${possibleParentItems}" name="parentItem.id" value="${assetSubItemInstance?.parentItem?.id}" noSelection="['null':'--None--']"></g:select>
+                                    </g:else>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="subItems">Sub Items:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'subItems','errors')}">
+                                    
+<ul>
+<g:each var="s" in="${assetSubItemInstance?.subItems?}">
+    <li><g:link controller="assetSubItemDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="assetSubItemDetailed" params="['parentItem.id':assetSubItemInstance?.id]" action="create">+Add Sub Item</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Maintenance Actions</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr> 
+                        
+                            <g:each var="m" in="${assetSubItemInstance?.maintenanceActions?}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:assetSubItemInstance,field:'maintenanceActions','errors')}">
+                                        <g:link controller="maintenanceActionDetailed" action="show" id="${m.id}">${m?.encodeAsHTML()}</g:link></li>
+                                    </td>
+                                </tr>
+                            </g:each>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:link controller="maintenanceActionDetailed" params="['assetSubItem.id':assetSubItemInstance?.id]" action="create">+Add Maintenance Action</g:link>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/search.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/search.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/search.gsp	(revision 875)
@@ -0,0 +1,138 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>AssetSubItem Search</title>
+        <nav:resources override="true"/>
+        <filterpane:includes />
+        <export:resource />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <filterpane:currentCriteria domainBean="AssetSubItem"
+                                    action="search"
+                                    dateFormat="EEE, dd-MMM-yyyy"
+                                    removeImgDir="images" 
+                                    removeImgFile="bullet_delete.png"
+                                    title="Search"/>
+
+            <div class="paginateButtons">
+                Results: ${assetSubItemInstanceList.size()} / ${assetSubItemInstanceTotal}
+                <span class="searchButtons">
+                    <filterpane:filterButton text="Search" appliedText="Change Search" />
+                </span>
+            </div>
+
+            <jsUtil:toggleControl toggleId="options"
+                                                    imageId="optionsImg"
+                                                    closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                    openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                    text="${g.message(code: 'default.options.text')}"
+                                                    />
+
+            <div id="options" style="display:none;">
+                <g:form method="post" action="setSearchParamsMax" >
+                    <g:hiddenField name="params" value="${filterParams}" />
+                    <div class="dialog">
+                        <table>
+                            <tbody>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Results per page:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <input type="text" maxlength="4" id="description" name="newMax" value="${params.max}"/>
+
+                                        <span class="buttons">
+                                            <g:actionSubmit action="setSearchParamsMax" class="go" value="Update" />
+                                        </span>
+                                    </td>
+                                </tr>
+
+                            </tbody>
+                        </table>
+                    </div>
+                </g:form>
+                <export:formats  params="${filterParams}" formats="['csv', 'excel', 'pdf', 'rtf']"/>
+            </div>
+
+            <br />
+
+            <g:if test="${assetSubItemInstanceList.size() > 10}">
+                <g:if test="${assetSubItemInstanceTotal > assetSubItemInstanceList.size()}">
+                    <div class="paginateButtons">
+                        <g:paginate action="search" total="${assetSubItemInstanceTotal}" params="${filterParams}" />
+                    </div>
+                </g:if>
+            </g:if>
+
+            <g:if test="${assetSubItemInstanceList.size() > 0}">
+                <div class="list">
+                    <table>
+                        <thead>
+                            <tr>
+                            
+                                <g:sortableColumn property="id" title="Id" params="${filterParams}" />
+
+                                <g:sortableColumn property="name" title="Name" params="${filterParams}" />
+                            
+                                <g:sortableColumn property="description" title="Description" params="${filterParams}" />
+
+                                <g:sortableColumn property="isActive" title="Is Active" params="${filterParams}" />
+
+                                <th></th>
+                            
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <g:each in="${assetSubItemInstanceList}" status="i" var="assetSubItemInstance">
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/assetSubItemDetailed/show/${assetSubItemInstance.id}"'>
+                                    ${fieldValue(bean:assetSubItemInstance, field:'id')}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/assetSubItemDetailed/show/${assetSubItemInstance.id}"'>
+                                    ${fieldValue(bean:assetSubItemInstance, field:'name')}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/assetSubItemDetailed/show/${assetSubItemInstance.id}"'>
+                                    ${fieldValue(bean:assetSubItemInstance, field:'description')}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/assetSubItemDetailed/show/${assetSubItemInstance.id}"'>
+                                    ${fieldValue(bean:assetSubItemInstance, field:'isActive')}
+                                </td>
+
+                                <td class="notClickable">
+                                    <g:link action="show" id="${assetSubItemInstance.id}">
+                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                    </g:link>
+                                </td>
+                            
+                            </tr>
+                        </g:each>
+                        </tbody>
+                    </table>
+                </div>
+            </g:if>
+            <div class="paginateButtons">
+                <g:paginate action="search" total="${assetSubItemInstanceTotal}" params="${filterParams}" />
+            </div>
+
+            <filterpane:filterPane domainBean="AssetSubItem"
+                                    title="Search"
+                                    action="search"
+                                    class="overlayPane"
+                                    excludeProperties="" />
+        </div> <!-- end body div -->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetSubItemDetailed/show.gsp	(revision 875)
@@ -0,0 +1,174 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show AssetSubItem</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="groupHeader">
+                                <label for="name">Asset Sub Item</label>
+                            </td>
+                            <td valign="top" class="value">
+                            </td>
+                        </tr>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Comment:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemInstance, field:'comment')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="groupHeader">Extended Attributes</td>
+                            <td  valign="top" style="text-align:left;" class="value">
+                            </td>
+                        </tr>
+                        
+                        <g:each var="a" in="${assetSubItemInstance.assetSubItemExtendedAttributes.sort { p1, p2 -> p1.extendedAttributeType.name.compareToIgnoreCase(p2.extendedAttributeType.name) }}">
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    ${a.extendedAttributeType.name.encodeAsHTML()}:
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <g:link controller="assetSubItemExtendedAttributeDetailed" action="edit" id="${a.id}">
+                                        ${a.value.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+
+                            </tr>
+                        </g:each>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="groupHeader">
+                                <label for="name">Asset Tree</label>
+                            </td>
+                            <td valign="top" class="value">
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Assets:</td>
+
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <g:if test="${assetSubItemInstance.parentItem}" >
+                                    N/A (Assigned to parent item)
+                                </g:if>
+                                <g:else>
+                                    <g:if test="${assetSubItemInstance.assets}">
+                                        <ul>
+                                        <g:each var="a" in="${ assetSubItemInstance.assets.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                                            <li><g:link controller="assetDetailed" action="show" id="${a.id}">${a?.encodeAsHTML()}</g:link></li>
+                                        </g:each>
+                                        </ul>
+                                    </g:if>
+                                    <g:else>
+                                        May be assigned via asset edit view.
+                                    </g:else>
+                                </g:else>
+                            </td>
+
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Parent Item:</td>
+                            
+                            <td valign="top" class="value">
+                                <g:if test="${assetSubItemInstance.assets}">
+                                     Level 1 sub item (Assigned directly to assets)
+                                </g:if>
+                                <g:else>
+                                    <g:link controller="assetSubItemDetailed" action="show" id="${assetSubItemInstance?.parentItem?.id}">
+                                        ${assetSubItemInstance?.parentItem?.encodeAsHTML()}
+                                    </g:link>
+                                </g:else>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="groupName">Sub Items:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="s" in="${assetSubItemInstance.subItems}">
+                                    <li><g:link controller="assetSubItemDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="groupHeader">
+                                <label for="name">Maintenance Actions</label>
+                            </td>
+                            <td valign="top" class="value">
+                            </td>
+                        </tr>
+                    
+                        <g:each var="m" in="${assetSubItemInstance.maintenanceActions}">
+                            <tr class="prop">
+                                <td valign="top" class="name"></td>
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <g:link controller="maintenanceActionDetailed" action="show" id="${m.id}">${m?.encodeAsHTML()}</g:link>
+                                </td>
+                            </tr>
+                        </g:each>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${assetSubItemInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,61 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create AssetSubItemExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetSubItemExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetSubItemExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            
+                            <tr class="prop">
+                              <td valign="top" class="name">
+                                      <label for="asset">Asset Sub Item:</label>
+                                 </td>
+
+                                 <td valign="top" class="value">
+                                     <g:link controller="assetSubItemDetailed" action="show" id="${assetSubItemExtendedAttributeInstance?.assetSubItem?.id}">
+                                          <g:hiddenField name="assetSubItem.id" value="${assetSubItemExtendedAttributeInstance?.assetSubItem.id}" />
+                                          ${assetSubItemExtendedAttributeInstance?.assetSubItem?.encodeAsHTML()}
+                                     </g:link>
+                                 </td>
+                             </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <g:select optionKey="id"
+                                                        from="${ExtendedAttributeType.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="extendedAttributeType.id"
+                                                        value="${assetSubItemExtendedAttributeInstance?.extendedAttributeType?.id}" >
+                                    </g:select>
+
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:assetSubItemExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,74 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit AssetSubItemExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${assetSubItemExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assetSubItemExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${assetSubItemExtendedAttributeInstance?.id}" />
+                <input type="hidden" name="version" value="${assetSubItemExtendedAttributeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:assetSubItemExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${assetSubItemExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="assetSubItem">Asset Sub Item:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemExtendedAttributeInstance,field:'assetSubItem','errors')}">
+                                    <g:select optionKey="id" from="${AssetSubItem.list()}" name="assetSubItem.id" value="${assetSubItemExtendedAttributeInstance?.assetSubItem?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assetSubItemExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${assetSubItemExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assetSubItemExtendedAttributeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,67 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show AssetSubItemExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemExtendedAttributeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Value:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemExtendedAttributeInstance, field:'value')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:assetSubItemExtendedAttributeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Asset Sub Item:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="assetSubItemDetailed" action="show" id="${assetSubItemExtendedAttributeInstance?.assetSubItem?.id}">${assetSubItemExtendedAttributeInstance?.assetSubItem?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Extended Attribute Type:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="extendedAttributeTypeDetailed" action="show" id="${assetSubItemExtendedAttributeInstance?.extendedAttributeType?.id}">${assetSubItemExtendedAttributeInstance?.extendedAttributeType?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${assetSubItemExtendedAttributeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/_personsInGroup.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/_personsInGroup.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/_personsInGroup.gsp	(revision 875)
@@ -0,0 +1,22 @@
+
+<table>
+    <tbody>
+        <tr class="prop">
+            <td valign="top" class="name">
+                <label for="persons">Persons in group (${personGroup.encodeAsHTML()}):</label>
+            </td>
+            <td valign="top" class="value">
+                <ul>
+                    <g:if test="${personsInGroup.size() > 0}">
+                        <g:each var="a" in="${personsInGroup}">
+                            <li>${a?.encodeAsHTML()}</li>
+                        </g:each>
+                    </g:if>
+                    <g:else>
+                        <li>None</li>
+                    </g:else>
+                </ul>
+            </td>
+        </tr>
+    </tbody>
+</table>
Index: /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/create.gsp	(revision 875)
@@ -0,0 +1,87 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create AssignedGroup</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Assigned Group</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${assignedGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assignedGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <g:hiddenField name="task.id" value="${assignedGroupInstance?.task?.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="task">Task:</label>
+                                </td>
+                                <td valign="top" class="name">
+                                    <g:link controller="taskDetailed" action="show" id="${assignedGroupInstance.task.id}" >
+                                        ${assignedGroupInstance?.task.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="personGroup">Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assignedGroupInstance,field:'personGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${PersonGroup.list().sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="personGroup.id"
+                                                        value="${assignedGroupInstance?.personGroup?.id}"
+                                                        onchange="${remoteFunction(action:'personsInGroup', update:'personsInGroup', params: '\'personGroup.id=\' + this.value' )}">
+                                    </g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Estimated Duration:</label>
+                                </td>
+
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:assignedGroupInstance,field:'estimatedHour','errors')}"
+                                        type="text" id="estimatedHour" name="estimatedHour" 
+                                        value="${fieldValue(bean:assignedGroupInstance,field:'estimatedHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:assignedGroupInstance,field:'estimatedMinute','errors')}"
+                                        type="text" id="estimatedMinute" name="estimatedMinute" 
+                                        value="${fieldValue(bean:assignedGroupInstance,field:'estimatedMinute')}" />
+                                    <g:helpBalloon code="assignedGroup.estimatedDuration" />
+                                </td> 
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+
+            <br />
+
+            <div id="personsInGroup" class="dialog">
+                <g:render template="personsInGroup" />
+            </div>
+
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assignedGroupDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,88 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit AssignedGroup</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Assigned Group</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${assignedGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assignedGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <g:hiddenField name="id" value="${assignedGroupInstance?.id}" />
+                <g:hiddenField name="task.id" value="${assignedGroupInstance?.task?.id}" />
+                <g:hiddenField name="version" value="${assignedGroupInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="task">Task:</label>
+                                </td>
+                                <td valign="top" class="name">
+                                    <g:link controller="taskDetailed" action="show" id="${assignedGroupInstance.task.id}" >
+                                        ${assignedGroupInstance?.task.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="personGroup">Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assignedGroupInstance,field:'personGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${PersonGroup.list().sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="personGroup.id"
+                                                        value="${assignedGroupInstance?.personGroup?.id}"
+                                                        onchange="${remoteFunction(action:'personsInGroup', update:'personsInGroup', params: '\'personGroup.id=\' + this.value' )}">
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Estimated Duration:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:assignedGroupInstance,field:'estimatedHour','errors')}"
+                                        type="text" id="estimatedHour" name="estimatedHour" 
+                                        value="${fieldValue(bean:assignedGroupInstance,field:'estimatedHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:assignedGroupInstance,field:'estimatedMinute','errors')}"
+                                        type="text" id="estimatedMinute" name="estimatedMinute" 
+                                        value="${fieldValue(bean:assignedGroupInstance,field:'estimatedMinute')}" />
+                                    <g:helpBalloon code="assignedGroup.estimatedDuration" />
+                                </td> 
+                            </tr>
+
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+
+            <br />
+
+            <div id="personsInGroup" class="dialog">
+                <g:render template="personsInGroup" />
+            </div>
+
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/_groupsForPerson.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/_groupsForPerson.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/_groupsForPerson.gsp	(revision 875)
@@ -0,0 +1,22 @@
+
+<table>
+    <tbody>
+        <tr class="prop">
+            <td valign="top" class="name">
+                <label for="groups">Groups for person (${person.encodeAsHTML()}):</label>
+            </td>
+            <td valign="top" class="value">
+                <ul>
+                    <g:if test="${groupsForPerson.size() > 0}">
+                        <g:each var="a" in="${groupsForPerson}">
+                            <li>${a?.encodeAsHTML()}</li>
+                        </g:each>
+                    </g:if>
+                    <g:else>
+                        <li>None</li>
+                    </g:else>
+                </ul>
+            </td>
+        </tr>
+    </tbody>
+</table>
Index: /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/create.gsp	(revision 875)
@@ -0,0 +1,86 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create AssignedPerson</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Assigned Person</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${assignedPersonInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assignedPersonInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <g:hiddenField name="task.id" value="${assignedPersonInstance?.task?.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="task">Task:</label>
+                                </td>
+                                <td valign="top" class="name">
+                                    <g:link controller="taskDetailed" action="show" id="${assignedPersonInstance.task.id}" >
+                                        ${assignedPersonInstance?.task.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="person">Person:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assignedPersonInstance,field:'person','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Person.list().sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                        name="person.id"
+                                                        value="${assignedPersonInstance?.person?.id}"
+                                                        onchange="${remoteFunction(action:'groupsForPerson', update:'groupsForPerson', params: '\'person.id=\' + this.value' )}">
+                                    </g:select>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Estimated Duration:</label>
+                                </td>
+
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:assignedPersonInstance,field:'estimatedHour','errors')}" 
+                                        type="text" id="estimatedHour" name="estimatedHour" 
+                                        value="${fieldValue(bean:assignedPersonInstance,field:'estimatedHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:assignedPersonInstance,field:'estimatedMinute','errors')}" 
+                                        type="text" id="estimatedMinute" name="estimatedMinute" 
+                                        value="${fieldValue(bean:assignedPersonInstance,field:'estimatedMinute')}" />
+                                    <g:helpBalloon code="assignedPerson.estimatedDuration" />
+                                </td> 
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+
+            <br />
+
+            <div id="groupsForPerson" class="dialog">
+                <g:render template="groupsForPerson" />
+            </div>
+
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/assignedPersonDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,88 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit AssignedPerson</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Assigned Person</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${assignedPersonInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${assignedPersonInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <g:hiddenField name="id" value="${assignedPersonInstance?.id}" />
+                <g:hiddenField name="task.id" value="${assignedPersonInstance?.task?.id}" />
+                <g:hiddenField name="version" value="${assignedPersonInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="task">Task:</label>
+                                </td>
+                                <td valign="top" class="name">
+                                    <g:link controller="taskDetailed" action="show" id="${assignedPersonInstance.task.id}" >
+                                        ${assignedPersonInstance?.task.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="person">Person:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:assignedPersonInstance,field:'person','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Person.list().sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                        name="person.id"
+                                                        value="${assignedPersonInstance?.person?.id}"
+                                                        onchange="${remoteFunction(action:'groupsForPerson', update:'groupsForPerson', params: '\'person.id=\' + this.value' )}">
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Estimated Duration:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:assignedPersonInstance,field:'estimatedHour','errors')}" 
+                                        type="text" id="estimatedHour" name="estimatedHour" 
+                                        value="${fieldValue(bean:assignedPersonInstance,field:'estimatedHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:assignedPersonInstance,field:'estimatedMinute','errors')}" 
+                                        type="text" id="estimatedMinute" name="estimatedMinute" 
+                                        value="${fieldValue(bean:assignedPersonInstance,field:'estimatedMinute')}" />
+                                    <g:helpBalloon code="assignedPerson.estimatedDuration" />
+                                </td> 
+                            </tr>
+
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+
+            <br />
+
+            <div id="groupsForPerson" class="dialog">
+                <g:render template="groupsForPerson" />
+            </div>
+
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/authority/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/authority/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/authority/create.gsp	(revision 875)
@@ -0,0 +1,50 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Create Authority</title>
+</head>
+
+<body>
+
+    <div class="nav">
+        <span class="menuButton"><g:link class="list" action="list">Authority List</g:link></span>
+    </div>
+
+    <div class="body">
+
+        <h1>Create Authority</h1>
+        <g:if test="${flash.message}">
+        <div class="message">${flash.message}</div>
+        </g:if>
+        <g:hasErrors bean="${authority}">
+        <div class="errors">
+        <g:renderErrors bean="${authority}" as="list" />
+        </div>
+        </g:hasErrors>
+
+        <g:form action="save">
+        <div class="dialog">
+        <table>
+        <tbody>
+            <tr class="prop">
+                <td valign="top" class="name"><label for="authority">Authority Name:</label></td>
+                <td valign="top" class="value ${hasErrors(bean:authority,field:'authority','errors')}">
+                    <input type="text" id="authority" name="authority" value="${authority?.authority?.encodeAsHTML()}"/>
+                </td>
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name"><label for="description">Description:</label></td>
+                <td valign="top" class="value ${hasErrors(bean:authority,field:'description','errors')}">
+                    <input type="text" id="description" name="description" value="${authority?.description?.encodeAsHTML()}"/>
+                </td>
+            </tr>
+        </tbody>
+        </table>
+        </div>
+
+        <div class="buttons">
+            <span class="button"><input class="save" type="submit" value="Create" /></span>
+        </div>
+        </g:form>
+    </div>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/authority/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/authority/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/authority/edit.gsp	(revision 875)
@@ -0,0 +1,68 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Edit Authority</title>
+</head>
+
+<body>
+
+    <div class="nav">
+        <span class="menuButton"><g:link class="list" action="list">Authority List</g:link></span>
+        <span class="menuButton"><g:link class="create" action="create">New Authority</g:link></span>
+    </div>
+
+    <div class="body">
+        <h1>Edit Authority</h1>
+        <g:if test="${flash.message}">
+        <div class="message">${flash.message}</div>
+        </g:if>
+        <g:hasErrors bean="${authority}">
+        <div class="errors">
+            <g:renderErrors bean="${authority}" as="list" />
+        </div>
+        </g:hasErrors>
+        <div class="prop">
+            <span class="name">ID:</span>
+            <span class="value">${authority.id}</span>
+        </div>
+        <g:form>
+            <input type="hidden" name="id" value="${authority.id}" />
+            <input type="hidden" name="version" value="${authority.version}" />
+            <div class="dialog">
+            <table>
+            <tbody>
+                <tr class="prop">
+                    <td valign="top" class="name"><label for="authority">Authority Name:</label></td>
+                    <td valign="top" class="value ${hasErrors(bean:authority,field:'authority','errors')}">
+                        <input type="text" id="authority" name="authority" value="${authority.authority?.encodeAsHTML()}"/>
+                    </td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name"><label for="description">Description:</label></td>
+                    <td valign="top" class="value ${hasErrors(bean:authority,field:'description','errors')}">
+                        <input type="text" id="description" name="description" value="${authority.description?.encodeAsHTML()}"/>
+                    </td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name"><label for="persons">Persons:</label></td>
+                    <td valign="top" class="value ${hasErrors(bean:authority,field:'persons','errors')}">
+                        <ul>
+                        <g:each var="p" in="${authority.persons?}">
+                            <li>${p}</li>
+                        </g:each>
+                        </ul>
+                    </td>
+                </tr>
+            </tbody>
+            </table>
+            </div>
+
+            <div class="buttons">
+                <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+            </div>
+
+        </g:form>
+    </div>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/authority/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/authority/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/authority/list.gsp	(revision 875)
@@ -0,0 +1,48 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Authority List</title>
+</head>
+
+<body>
+
+    <div class="nav">
+        <span class="menuButton"><g:link class="create" action="create">New Authority</g:link></span>
+    </div>
+
+    <div class="body">
+        <h1>Authority List</h1>
+        <g:if test="${flash.message}">
+        <div class="message">${flash.message}</div>
+        </g:if>
+        <div class="list">
+            <table>
+            <thead>
+                <tr>
+                    <g:sortableColumn property="id" title="ID" />
+                    <g:sortableColumn property="authority" title="Authority Name" />
+                    <g:sortableColumn property="description" title="Description" />
+                    <th>&nbsp;</th>
+                </tr>
+            </thead>
+            <tbody>
+            <g:each in="${authorityList}" status="i" var="authority">
+                <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                    <td>${authority.id}</td>
+                    <td>${authority.authority?.encodeAsHTML()}</td>
+                    <td>${authority.description?.encodeAsHTML()}</td>
+                    <td class="actionButtons">
+                        <span class="actionButton">
+                            <g:link action="show" id="${authority.id}">Show</g:link>
+                        </span>
+                    </td>
+                </tr>
+            </g:each>
+            </tbody>
+            </table>
+        </div>
+
+        <div class="paginateButtons">
+            <g:paginate total="${Authority.count()}" />
+        </div>
+    </div>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/authority/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/authority/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/authority/show.gsp	(revision 875)
@@ -0,0 +1,56 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Show Authority</title>
+</head>
+
+<body>
+
+    <div class="nav">
+        <span class="menuButton"><g:link class="list" action="list">Authority List</g:link></span>
+        <span class="menuButton"><g:link class="create" action="create">New Authority</g:link></span>
+    </div>
+
+    <div class="body">
+        <h1>Show Authority</h1>
+        <g:if test="${flash.message}">
+        <div class="message">${flash.message}</div>
+        </g:if>
+        <div class="dialog">
+            <table>
+            <tbody>
+
+                <tr class="prop">
+                    <td valign="top" class="name">ID:</td>
+                    <td valign="top" class="value">${authority.id}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Authority Name:</td>
+                    <td valign="top" class="value">${authority.authority}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Description:</td>
+                    <td valign="top" class="value">${authority.description}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Persons:</td>
+                    <td valign="top" class="value">${authority.persons}</td>
+                </tr>
+
+            </tbody>
+            </table>
+        </div>
+
+        <div class="buttons">
+            <g:form>
+                <input type="hidden" name="id" value="${authority?.id}" />
+                <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+            </g:form>
+        </div>
+
+    </div>
+
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/contactDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/contactDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/contactDetailed/create.gsp	(revision 875)
@@ -0,0 +1,94 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Contact</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Contact</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${contactInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${contactInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            
+                            <g:if test="${contactInstance.supplier}">
+                                <g:hiddenField name="supplier.id" value="${contactInstance.supplier.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="supplier">Supplier:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:contactInstance,field:'supplier','errors')}">
+                                        <g:link controller="supplierDetailed" action="show" id="${contactInstance.supplier.id}">
+                                            ${contactInstance.supplier.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr>
+                            </g:if>
+                            
+                            <g:if test="${contactInstance.person}">
+                                <g:hiddenField name="person.id" value="${contactInstance.person.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="person">Person:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="person" action="show" id="${contactInstance.person.id}">
+                                            ${contactInstance.person.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr> 
+                            </g:if>
+                            
+                            <g:if test="${contactInstance.site}">
+                                <g:hiddenField name="site.id" value="${contactInstance.site.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="site">Site:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="siteDetailed" action="show" id="${contactInstance.site.id}">
+                                            ${contactInstance.site.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr> 
+                            </g:if>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="contactType">Contact Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:contactInstance,field:'contactType','errors')}">
+                                    <g:select optionKey="id" from="${ContactType.list()}" name="contactType.id" value="${contactInstance?.contactType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="email">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:contactInstance,field:'value','errors')}">
+                                    <input type="text" id="value" name="value" value="${fieldValue(bean:contactInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/contactDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/contactDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/contactDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,98 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Contact</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Contact</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${contactInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${contactInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${contactInstance?.id}" />
+                <input type="hidden" name="version" value="${contactInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <g:if test="${contactInstance.supplier}">
+                                <g:hiddenField name="supplier.id" value="${contactInstance.supplier.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="supplier">Supplier:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:contactInstance,field:'supplier','errors')}">
+                                        <g:link controller="supplierDetailed" action="show" id="${contactInstance.supplier.id}">
+                                            ${contactInstance.supplier.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <g:if test="${contactInstance.person}">
+                                <g:hiddenField name="person.id" value="${contactInstance.person.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="person">Person:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="person" action="show" id="${contactInstance.person.id}">
+                                            ${contactInstance.person.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <g:if test="${contactInstance.site}">
+                                <g:hiddenField name="site.id" value="${contactInstance.site.id}"/>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="site">Site:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link controller="siteDetailed" action="show" id="${contactInstance.site.id}">
+                                            ${contactInstance.site.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="contactType">Contact Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:contactInstance,field:'contactType','errors')}">
+                                    <g:select optionKey="id" from="${ContactType.list()}" name="contactType.id" value="${contactInstance?.contactType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="email">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:contactInstance,field:'value','errors')}">
+                                    <input type="text" id="value" name="value" value="${fieldValue(bean:contactInstance,field:'value')}"/>
+                                </td>
+                            </tr>
+
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/contactDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/contactDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/contactDetailed/show.gsp	(revision 875)
@@ -0,0 +1,73 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Contact</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Contact</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            <td valign="top" class="value">${fieldValue(bean:contactInstance, field:'id')}</td>
+                        </tr>
+
+                        <g:if test="${contactInstance.supplier}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Supplier:</td>
+
+                                <td valign="top" class="value"><g:link controller="supplierDetailed" action="show" id="${contactInstance.supplier.id}">${contactInstance.supplier.encodeAsHTML()}</g:link></td>
+
+                            </tr>
+                        </g:if>
+
+                        <g:if test="${contactInstance.person}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Person:</td>
+
+                                <td valign="top" class="value"><g:link controller="person" action="show" id="${contactInstance.person.id}">${contactInstance.person.encodeAsHTML()}</g:link></td>
+
+                            </tr>
+                        </g:if>
+
+                        <g:if test="${contactInstance.site}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Site:</td>
+
+                                <td valign="top" class="value"><g:link controller="siteDetailed" action="show" id="${contactInstance.site.id}">${contactInstance.site.encodeAsHTML()}</g:link></td>
+
+                            </tr>
+                        </g:if>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Contact Type:</td>
+                            <td valign="top" class="value">${fieldValue(bean:contactInstance, field:'contactType')}</td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Value:</td>
+                            <td valign="top" class="value">${fieldValue(bean:contactInstance, field:'value')}</td>
+                        </tr>
+
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${contactInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,78 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create CostCode</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${costCodeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${costCodeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:costCodeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="purchasingGroup">Purchasing Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'purchasingGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                    from="${PurchasingGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                    name="purchasingGroup.id"
+                                                    value="${costCodeInstance?.purchasingGroup?.id}" >
+                                    </g:select>
+                                    <p>
+                                        <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                                    </p>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:costCodeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${costCodeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,82 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit CostCode</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${costCodeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${costCodeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${costCodeInstance?.id}" />
+                <input type="hidden" name="version" value="${costCodeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:costCodeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="purchasingGroup">Purchasing Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'purchasingGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                    from="${PurchasingGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                    name="purchasingGroup.id"
+                                                    value="${costCodeInstance?.purchasingGroup?.id}" >
+                                    </g:select>
+                                    <p>
+                                        <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                                    </p>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:costCodeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:costCodeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${costCodeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/list.gsp	(revision 875)
@@ -0,0 +1,75 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>CostCode List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                            <g:sortableColumn property="purchasingGroup" title="Group" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${costCodeInstanceList}" status="i" var="costCodeInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/costCodeDetailed/show/${costCodeInstance.id}"'>
+                                ${fieldValue(bean:costCodeInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/costCodeDetailed/show/${costCodeInstance.id}"'>
+                                ${fieldValue(bean:costCodeInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/costCodeDetailed/show/${costCodeInstance.id}"'>
+                                ${fieldValue(bean:costCodeInstance, field:'purchasingGroup')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/costCodeDetailed/show/${costCodeInstance.id}"'>
+                                ${fieldValue(bean:costCodeInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/costCodeDetailed/show/${costCodeInstance.id}"'>
+                                ${fieldValue(bean:costCodeInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${costCodeInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${costCodeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/costCodeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,70 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show CostCode</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:costCodeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:costCodeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Purchasing Group:</td>
+                            <td valign="top" class="value">
+                                <g:link controller="purchasingGroupDetailed" action="show" id="${costCodeInstance?.purchasingGroup?.id}">
+                                    ${costCodeInstance?.purchasingGroup?.encodeAsHTML()}
+                                </g:link>
+                            </td>
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:costCodeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:costCodeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${costCodeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/create.gsp	(revision 875)
@@ -0,0 +1,71 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Department</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${departmentInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${departmentInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:departmentInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:departmentInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:departmentInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${departmentInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,123 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Department</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${departmentInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${departmentInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${departmentInstance?.id}" />
+                <input type="hidden" name="version" value="${departmentInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:departmentInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:departmentInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:departmentInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${departmentInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="departmentExtendedAttributes">Department Extended Attributes:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'departmentExtendedAttributes','errors')}">
+                                    
+<ul>
+<g:each var="d" in="${departmentInstance?.departmentExtendedAttributes?}">
+    <li><g:link controller="departmentExtendedAttributeDetailed" action="show" id="${d.id}">${d?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="departmentExtendedAttributeDetailed" params="['department.id':departmentInstance?.id]" action="create">+Add Extended Attribute</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="persons">Persons:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'persons','errors')}">
+                                    
+<ul>
+<g:each var="p" in="${departmentInstance?.persons?}">
+    <li><g:link controller="person" action="show" id="${p.id}">${p?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="person" params="['department.id':departmentInstance?.id]" action="create">+Add Person</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="sections">Sections:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentInstance,field:'sections','errors')}">
+                                    
+<ul>
+<g:each var="s" in="${departmentInstance?.sections?}">
+    <li><g:link controller="sectionDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="sectionDetailed" params="['department.id':departmentInstance?.id]" action="create">+Add Section</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/list.gsp	(revision 875)
@@ -0,0 +1,69 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Department List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${departmentInstanceList}" status="i" var="departmentInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/departmentDetailed/show/${departmentInstance.id}"'>
+                                ${fieldValue(bean:departmentInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/departmentDetailed/show/${departmentInstance.id}"'>
+                                ${fieldValue(bean:departmentInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/departmentDetailed/show/${departmentInstance.id}"'>
+                                ${fieldValue(bean:departmentInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/departmentDetailed/show/${departmentInstance.id}"'>
+                                ${fieldValue(bean:departmentInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${departmentInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${departmentInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/departmentDetailed/show.gsp	(revision 875)
@@ -0,0 +1,107 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Department</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Comment:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentInstance, field:'comment')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Department Extended Attributes:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="d" in="${departmentInstance.departmentExtendedAttributes}">
+                                    <li><g:link controller="departmentExtendedAttributeDetailed" action="show" id="${d.id}">${d?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Persons:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="p" in="${departmentInstance.persons}">
+                                    <li><g:link controller="person" action="show" id="${p.id}">${p?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Sections:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="s" in="${departmentInstance.sections}">
+                                    <li><g:link controller="sectionDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${departmentInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,70 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create DepartmentExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Department Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${departmentExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${departmentExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:departmentExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${departmentExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="department">Department:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'department','errors')}">
+                                    <g:select optionKey="id" from="${Department.list()}" name="department.id" value="${departmentExtendedAttributeInstance?.department?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${departmentExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,74 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit DepartmentExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Department Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${departmentExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${departmentExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${departmentExtendedAttributeInstance?.id}" />
+                <input type="hidden" name="version" value="${departmentExtendedAttributeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:departmentExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${departmentExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="department">Department:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'department','errors')}">
+                                    <g:select optionKey="id" from="${Department.list()}" name="department.id" value="${departmentExtendedAttributeInstance?.department?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:departmentExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${departmentExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/departmentExtendedAttributeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,67 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show DepartmentExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Department Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentExtendedAttributeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Value:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentExtendedAttributeInstance, field:'value')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:departmentExtendedAttributeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Department:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="departmentDetailed" action="show" id="${departmentExtendedAttributeInstance?.department?.id}">${departmentExtendedAttributeInstance?.department?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Extended Attribute Type:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="extendedAttributeTypeDetailed" action="show" id="${departmentExtendedAttributeInstance?.extendedAttributeType?.id}">${departmentExtendedAttributeInstance?.extendedAttributeType?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${departmentExtendedAttributeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/entryDetailed/_create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryDetailed/_create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryDetailed/_create.gsp	(revision 875)
@@ -0,0 +1,133 @@
+
+
+    <g:render template="/shared/messages" />
+    <g:hasErrors bean="${entryInstance}">
+        <div class="errors">
+            <g:renderErrors bean="${entryInstance}" as="list" />
+        </div>
+    </g:hasErrors>
+    <div class="pane_close">
+        <img  src="${resource(dir:'images/skin',file:'cross.png')}" alt="Close" title="Close"/>
+    </div>
+    <g:form action="ajaxSave" method="post" name="createEntryForm">
+        <g:hiddenField name="task.id" value="${entryInstance.task.id}" />
+        <g:hiddenField name="entryType.id" value="${entryInstance.entryType.id}" />
+        <g:hiddenField name="submitAction" value="submit_default" />
+        <div class="dialog">
+            <table>
+                <tbody>
+
+                    <g:if test="${entryInstance?.entryType?.id == 1}">
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label for="productionReference">Production:</label>
+                            </td>
+                            <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'productionReference','errors')}">
+                                <g:select optionKey="id"
+                                                    from="${ProductionReference.findAllByIsActive(true)}"
+                                                    name="productionReference.id"
+                                                    value="${entryInstance.productionReference?.id}"
+                                                    noSelection="['null':'--None--']">
+                                </g:select>
+                                <custom:helpBalloon code="entry.productionReference.fault" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                            </td>
+                        </tr>
+                    </g:if>
+
+                    <g:if test="${entryInstance?.entryType?.id == 6}">
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label for="highestSeverity">Condition Severity:</label>
+                            </td>
+                            <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'highestSeverity','errors')}">
+                                <g:select optionKey="id"
+                                                    from="${ConditionSeverity.findAllByIsActive(true)}"
+                                                    name="highestSeverity.id"
+                                                    value="${entryInstance.highestSeverity?.id}"
+                                                    noSelection="['null':/${g.message(code:'default.please.select.text')}/]" >
+                                </g:select>
+                                <custom:helpBalloon code="entry.comment.pm.entry" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                            </td>
+                        </tr>
+                    </g:if>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="comment">${entryInstance?.entryType.encodeAsHTML()}:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'comment','errors')}">
+                            <textarea rows="5" cols="40" name="comment">${fieldValue(bean:entryInstance, field:'comment')}</textarea>
+                            <g:if test="${entryInstance?.entryType?.id == 1}">
+                                <custom:helpBalloon code="entry.comment.fault" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                            </g:if>
+                            <g:elseif test="${entryInstance?.entryType?.id == 2}">
+                                <custom:helpBalloon code="entry.comment.cause" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                            </g:elseif>
+                            <g:elseif test="${entryInstance?.entryType?.id == 3}">
+                                <custom:helpBalloon code="entry.comment.work.done" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                            </g:elseif>
+                            <g:elseif test="${entryInstance?.entryType?.id == 6}">
+                                <custom:helpBalloon code="entry.comment.pm.entry" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                            </g:elseif>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="dateDone">Date Done:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'dateDone','errors')}">
+                            <richui:dateChooser name="dateDone" format="dd-MM-yyyy" value="${entryInstance.dateDone}" />
+                            <custom:helpBalloon code="entry.date.done" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                        </td>
+                    </tr>
+
+                    <g:if test="${entryInstance?.entryType?.id != 2}">
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label for="durationHour">Duration:</label>
+                            </td>
+
+                            <td valign="top" class="value">
+                                <input class="time ${hasErrors(bean:entryInstance,field:'durationHour','errors')}"
+                                    type="text" id="durationHour" name="durationHour"
+                                    value="${fieldValue(bean:entryInstance,field:'durationHour')}" />
+                                :
+                                <input class="time ${hasErrors(bean:entryInstance,field:'durationMinute','errors')}"
+                                    type="text" id="durationMinute" name="durationMinute"
+                                    value="${fieldValue(bean:entryInstance,field:'durationMinute')}" />
+                                <custom:helpBalloon code="entry.duration" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                            </td>
+                        </tr>
+                    </g:if>
+
+                </tbody>
+            </table>
+        </div>
+        <div class="buttons">
+            <span class="button">
+                <input class="save" type="submit" value="Save" />
+            </span>
+            <custom:helpBalloon code="task.save.entry"
+                                            iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+            <span class="button">
+                <input class="flag" type="button" value="Unresolved" name="submit_andSetAttentionFlag" />
+            </span>
+            <custom:helpBalloon code="task.status.unresolved.save.entry"
+                                            iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+            <span class="button">
+                <g:if test="${entryInstance.task.attentionFlag}" >
+                    <input class="complete"
+                                type="button" 
+                                value="Resolved"
+                                onclick="submit_confirmResult = confirm('${message(code:'task.clear.attention.flag.on.completion.confirm')}');"
+                                name="submit_andComplete"/>
+                </g:if>
+                <g:else>
+                    <input class="complete" type="button" value="Resolved" name="submit_andComplete" />
+                </g:else>
+            </span>
+            <custom:helpBalloon code="task.status.resolved.save.entry"
+                                            iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+        </div>
+    </g:form>
Index: /branches/features/grailsUpgrade/grails-app/views/entryDetailed/_list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryDetailed/_list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryDetailed/_list.gsp	(revision 875)
@@ -0,0 +1,87 @@
+
+        <h1>
+            <g:if test="${entryList[0].entryType.id == 1}">
+                Faults
+            </g:if>
+            <g:if test="${entryList[0].entryType.id == 2}">
+                Causes
+            </g:if>
+            <g:if test="${entryList[0].entryType.id == 3}">
+                Work Done
+            </g:if>
+            <g:if test="${entryList[0].entryType.id == 6}">
+                PM Entries
+            </g:if>
+        </h1>
+        <div class="list">
+            <table>
+                <thead>
+                    <tr>
+                        <g:if test="${entryList[0].entryType.id == 6}">
+                            <th>
+                                <img src="${resource(dir:'images/skin',file:'award_star_silver_3.png')}"
+                                        alt="Severity"
+                                        title="Highest Severity"  />
+                            </th>
+                        </g:if>
+                        <th>Comment</th>
+                        <th>Date Done</th>
+                        <g:if test="${(entryList[0].entryType.id == 3) || (entryList[0].entryType.id == 6)}">
+                            <th>Duration</th>
+                        </g:if>
+                        <g:if test="${entryList[0].entryType.id == 1}">
+                            <th>Production</th>
+                            <th>Down Time</th>
+                        </g:if>
+                        <th>Entered By</th>
+                        <th></th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <g:each in="${entryList}" status="i" var="entry">
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                                <g:if test="${entryList[0]?.entryType?.id == 6}">
+                                    <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                        ${entry.highestSeverity.code.encodeAsHTML()}
+                                    </td>
+                                </g:if>
+
+                                <td width="65%" onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                    ${entry.comment.encodeAsHTML()}
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                    <g:formatDate date="${entry.dateDone}" format="EEE, dd-MMM-yyyy"/>
+                                </td>
+
+                                <g:if test="${(entryList[0].entryType.id == 3) || (entryList[0].entryType.id == 6)}">
+                                    <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                        ${entry.durationHour}:${entry.durationMinute}
+                                    </td>
+                                </g:if>
+
+                                <g:if test="${entryList[0].entryType.id == 1}">
+                                    <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                        ${fieldValue(bean:entry, field:'productionReference')}
+                                    </td>
+                                    <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                        ${entry.durationHour}:${entry.durationMinute}
+                                    </td>
+                                </g:if>
+
+                                <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                    ${entry.enteredBy.encodeAsHTML()}
+                                </td>
+
+                                <td class="notClickable">
+                                    <g:link controller="entryDetailed" action="edit" id="${entry.id}">
+                                        <img  src="${resource(dir:'images/skin',file:'database_edit.png')}" alt="Edit" title="Edit" />
+                                    </g:link>
+                                </td>
+
+                            </tr>
+                    </g:each>
+                </tbody>
+            </table>
+        </div>
Index: /branches/features/grailsUpgrade/grails-app/views/entryDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryDetailed/create.gsp	(revision 875)
@@ -0,0 +1,113 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Entry</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Entry</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${entryInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${entryInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <g:hiddenField name="task.id" value="${entryInstance.task.id}" />
+                <g:hiddenField name="entryType.id" value="${entryInstance.entryType.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="task">Task:</label>
+                                </td>
+                                <td valign="top" class="name">
+                                    <g:link controller="taskDetailed" action="show" id="${entryInstance.task.id}" >
+                                        ${entryInstance?.task.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">${entryInstance?.entryType.encodeAsHTML()}:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:entryInstance, field:'comment')}</textarea>
+                                    <g:if test="${entryInstance?.entryType?.id == 1}">
+                                        <g:helpBalloon code="entry.comment.fault" />
+                                    </g:if>
+                                    <g:elseif test="${entryInstance?.entryType?.id == 2}">
+                                        <g:helpBalloon code="entry.comment.cause" />
+                                    </g:elseif>
+                                    <g:elseif test="${entryInstance?.entryType?.id == 3}">
+                                        <g:helpBalloon code="entry.comment.work.done" />
+                                    </g:elseif>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="dateDone">Date Done:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'dateDone','errors')}">
+                                    <richui:dateChooser name="dateDone" format="dd-MM-yyyy" value="${entryInstance.dateDone}" />
+                                    <g:helpBalloon code="entry.date.done" />
+                                </td>
+                            </tr>
+
+                            <g:if test="${entryInstance?.entryType?.id == 1}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="productionReference">Production:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'productionReference','errors')}">
+                                        <g:select optionKey="id"
+                                                            from="${ProductionReference.findAllByIsActive(true)}"
+                                                            name="productionReference.id"
+                                                            value="${entryInstance.productionReference?.id}"
+                                                            noSelection="['null':'--None--']">
+                                        </g:select>
+                                        <g:helpBalloon code="entry.productionReference.fault" />
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <g:if test="${entryInstance?.entryType?.id != 2}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="durationHour">Duration:</label>
+                                    </td>
+
+                                    <td valign="top" class="value">
+                                        <input class="time ${hasErrors(bean:entryInstance,field:'durationHour','errors')}" 
+                                            type="text" id="durationHour" name="durationHour" 
+                                            value="${fieldValue(bean:entryInstance,field:'durationHour')}" />
+                                        :
+                                        <input class="time ${hasErrors(bean:entryInstance,field:'durationMinute','errors')}" 
+                                            type="text" id="durationMinute" name="durationMinute" 
+                                            value="${fieldValue(bean:entryInstance,field:'durationMinute')}" />
+                                        <g:helpBalloon code="entry.duration" />
+                                    </td>
+                                </tr>
+                            </g:if>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/entryDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,149 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Entry</title>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Entry</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${entryInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${entryInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${entryInstance?.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="task">Task:</label>
+                                </td>
+                                <td valign="top" class="name">
+                                    <g:link controller="taskDetailed" action="show" id="${entryInstance.task.id}" >
+                                        ${entryInstance?.task.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+
+                            <g:if test="${entryInstance?.entryType?.id == 1}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="productionReference">Production:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'productionReference','errors')}">
+                                        <g:select optionKey="id"
+                                                            from="${ProductionReference.findAllByIsActive(true)}"
+                                                            name="productionReference.id"
+                                                            value="${entryInstance.productionReference?.id}"
+                                                            noSelection="['null':'--None--']">
+                                        </g:select>
+                                        <g:helpBalloon code="entry.productionReference.fault" />
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <g:if test="${entryInstance?.entryType?.id == 6}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="highestSeverity">Condition Severity:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'highestSeverity','errors')}">
+                                        <g:select optionKey="id"
+                                                            from="${ConditionSeverity.findAllByIsActive(true)}"
+                                                            name="highestSeverity.id"
+                                                            value="${entryInstance.highestSeverity?.id}"
+                                                            noSelection="['null':/${g.message(code:'default.please.select.text')}/]" >
+                                        </g:select>
+                                        <custom:helpBalloon code="entry.comment.pm.entry" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+                                    </td>
+                                </tr>
+                            </g:if>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:entryInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="dateDone">Date Done:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'dateDone','errors')}">
+                                    <richui:dateChooser name="dateDone" format="dd-MM-yyyy" value="${entryInstance?.dateDone}" />
+                                </td>
+                            </tr>
+
+                            <g:if test="${entryInstance?.entryType?.id != 2}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="durationHour">Duration:</label>
+                                    </td>
+
+                                    <td valign="top" class="value">
+                                        <input class="time ${hasErrors(bean:entryInstance,field:'durationHour','errors')}" 
+                                            type="text" id="durationHour" name="durationHour" 
+                                            value="${fieldValue(bean:entryInstance,field:'durationHour')}" />
+                                        :
+                                        <input class="time ${hasErrors(bean:entryInstance,field:'durationMinute','errors')}" 
+                                            type="text" id="durationMinute" name="durationMinute" 
+                                            value="${fieldValue(bean:entryInstance,field:'durationMinute')}" />
+                                        <g:helpBalloon code="entry.duration" />
+                                    </td>
+                                </tr>
+                            </g:if>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="dateEntered">Date Entered:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:formatDate date="${entryInstance?.dateEntered}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="enteredBy">Entered By:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    ${entryInstance?.enteredBy?.toString()}
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="entryType">Entry Type:</label>
+                                </td>
+                                <td valign="top" class="name">
+                                        ${entryInstance?.entryType.encodeAsHTML()}
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/entryDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryDetailed/show.gsp	(revision 875)
@@ -0,0 +1,114 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Entry</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Entry</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:entryInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Task:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="taskDetailed" action="show" id="${entryInstance?.task?.id}">${entryInstance?.task?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+
+                        <g:if test="${entryInstance.productionReference}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Production:</td>
+
+                                <td valign="top" class="value">
+                                    ${fieldValue(bean:entryInstance, field:'productionReference')}
+                                </td>
+
+                            </tr>
+                        </g:if>
+
+                        <g:if test="${entryInstance.highestSeverity}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Condition Severity:</td>
+
+                                <td valign="top" class="value">
+                                    ${fieldValue(bean:entryInstance, field:'highestSeverity')}
+                                </td>
+
+                            </tr>
+                        </g:if>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Comment:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:entryInstance, field:'comment')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Date Done:</td>
+                            
+                            <td valign="top" class="value">
+                                <g:formatDate date="${entryInstance.dateDone}" format="EEE, dd-MMM-yyyy"/>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Duration:</td>
+                            <td valign="top" class="value">${entryInstance.durationHour}h : ${entryInstance.durationMinute}min</td>
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Date Entered:</td>
+                            
+                            <td valign="top" class="value">
+                                <g:formatDate date="${entryInstance.dateEntered}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Entered By:</td>
+                            
+                            <td valign="top" class="value">${entryInstance?.enteredBy?.encodeAsHTML()}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Entry Type:</td>
+                            
+                            <td valign="top" class="value">${entryInstance?.entryType?.encodeAsHTML()}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${entryInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/entryType/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryType/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryType/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create EntryType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">EntryType List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create EntryType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${entryTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${entryTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:entryTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${entryTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:entryTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/entryType/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryType/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryType/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit EntryType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">EntryType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New EntryType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit EntryType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${entryTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${entryTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${entryTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${entryTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:entryTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="entries">Entries:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryTypeInstance,field:'entries','errors')}">
+                                    
+<ul>
+<g:each var="e" in="${entryTypeInstance?.entries?}">
+    <li><g:link controller="entry" action="show" id="${e.id}">${e?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="entry" params="['entryType.id':entryTypeInstance?.id]" action="create">Add Entry</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${entryTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:entryTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/entryType/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryType/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryType/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>EntryType List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New EntryType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>EntryType List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${entryTypeInstanceList}" status="i" var="entryTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${entryTypeInstance.id}">${fieldValue(bean:entryTypeInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:entryTypeInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:entryTypeInstance, field:'isActive')}</td>
+                        
+                            <td>${fieldValue(bean:entryTypeInstance, field:'name')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${entryTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/entryType/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/entryType/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/entryType/show.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show EntryType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">EntryType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New EntryType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show EntryType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:entryTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:entryTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Entries:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="e" in="${entryTypeInstance.entries}">
+                                    <li><g:link controller="entry" action="show" id="${e.id}">${e?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:entryTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:entryTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${entryTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/error.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/error.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/error.gsp	(revision 875)
@@ -0,0 +1,54 @@
+<html>
+  <head>
+	  <title>Grails Runtime Exception</title>
+	  <style type="text/css">
+	  		.message {
+	  			border: 1px solid black;
+	  			padding: 5px;
+	  			background-color:#E9E9E9;
+	  		}
+	  		.stack {
+	  			border: 1px solid black;
+	  			padding: 5px;
+	  			overflow:auto;
+	  			height: 300px;
+	  		}
+	  		.snippet {
+	  			padding: 5px;
+	  			background-color:white;
+	  			border:1px solid black;
+	  			margin:3px;
+	  			font-family:courier;
+	  		}
+	  </style>
+  </head>
+
+  <body>
+    <h1>Grails Runtime Exception</h1>
+    <h2>Error Details</h2>
+
+  	<div class="message">
+		<strong>Error ${request.'javax.servlet.error.status_code'}:</strong> ${request.'javax.servlet.error.message'.encodeAsHTML()}<br/>
+		<strong>Servlet:</strong> ${request.'javax.servlet.error.servlet_name'}<br/>
+		<strong>URI:</strong> ${request.'javax.servlet.error.request_uri'}<br/>
+		<g:if test="${exception}">
+	  		<strong>Exception Message:</strong> ${exception.message?.encodeAsHTML()} <br />
+	  		<strong>Caused by:</strong> ${exception.cause?.message?.encodeAsHTML()} <br />
+	  		<strong>Class:</strong> ${exception.className} <br />
+	  		<strong>At Line:</strong> [${exception.lineNumber}] <br />
+	  		<strong>Code Snippet:</strong><br />
+	  		<div class="snippet">
+	  			<g:each var="cs" in="${exception.codeSnippet}">
+	  				${cs?.encodeAsHTML()}<br />
+	  			</g:each>
+	  		</div>
+		</g:if>
+  	</div>
+	<g:if test="${exception}">
+	    <h2>Stack Trace</h2>
+	    <div class="stack">
+	      <pre><g:each in="${exception.stackTraceLines}">${it.encodeAsHTML()}<br/></g:each></pre>
+	    </div>
+	</g:if>
+  </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create ExtendedAttributeType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${extendedAttributeTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${extendedAttributeTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:extendedAttributeTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:extendedAttributeTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:extendedAttributeTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:extendedAttributeTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:extendedAttributeTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${extendedAttributeTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,68 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit ExtendedAttributeType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${extendedAttributeTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${extendedAttributeTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${extendedAttributeTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${extendedAttributeTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:extendedAttributeTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:extendedAttributeTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:extendedAttributeTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:extendedAttributeTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:extendedAttributeTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${extendedAttributeTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/list.gsp	(revision 875)
@@ -0,0 +1,71 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>ExtendedAttributeType List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                            <g:sortableColumn property="id" title="Id" />
+
+                            <g:sortableColumn property="name" title="Name" />
+
+                            <g:sortableColumn property="description" title="Description" />
+
+                            <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${extendedAttributeTypeInstanceList}" status="i" var="extendedAttributeTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/extendedAttributeTypeDetailed/show/${extendedAttributeTypeInstance.id}"'>
+                                ${fieldValue(bean:extendedAttributeTypeInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/extendedAttributeTypeDetailed/show/${extendedAttributeTypeInstance.id}"'>
+                                ${fieldValue(bean:extendedAttributeTypeInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/extendedAttributeTypeDetailed/show/${extendedAttributeTypeInstance.id}"'>
+                                ${fieldValue(bean:extendedAttributeTypeInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/extendedAttributeTypeDetailed/show/${extendedAttributeTypeInstance.id}"'>
+                                ${fieldValue(bean:extendedAttributeTypeInstance, field:'isActive')}
+                            </td>
+                            
+                            <td class="notClickable">
+                                <g:link action="show" id="${extendedAttributeTypeInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${extendedAttributeTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/extendedAttributeTypeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,63 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show ExtendedAttributeType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:extendedAttributeTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:extendedAttributeTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:extendedAttributeTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:extendedAttributeTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${extendedAttributeTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/index.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/index.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/index.gsp	(revision 875)
@@ -0,0 +1,1 @@
+<%response.sendRedirect(request.getContextPath()+'/appCore/')%>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:inventoryGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:inventoryGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit InventoryGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${inventoryGroupInstance?.id}" />
+                <input type="hidden" name="version" value="${inventoryGroupInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:inventoryGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:inventoryGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItems">Inventory Items:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryGroupInstance,field:'inventoryItems','errors')}">
+                                    
+<ul>
+<g:each var="i" in="${inventoryGroupInstance?.inventoryItems?}">
+    <li><g:link controller="inventoryItemDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="inventoryItemDetailed" params="['inventoryGroup.id':inventoryGroupInstance?.id]" action="create">+Add Inventory Item</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/list.gsp	(revision 875)
@@ -0,0 +1,71 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>InventoryGroup List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                            <g:sortableColumn property="id" title="Id" />
+
+                            <g:sortableColumn property="name" title="Name" />
+
+                            <g:sortableColumn property="description" title="Description" />
+
+                            <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${inventoryGroupInstanceList}" status="i" var="inventoryGroupInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryGroupDetailed/show/${inventoryGroupInstance.id}"'>
+                                ${fieldValue(bean:inventoryGroupInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryGroupDetailed/show/${inventoryGroupInstance.id}"'>
+                                ${fieldValue(bean:inventoryGroupInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryGroupDetailed/show/${inventoryGroupInstance.id}"'>
+                                ${fieldValue(bean:inventoryGroupInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryGroupDetailed/show/${inventoryGroupInstance.id}"'>
+                                ${fieldValue(bean:inventoryGroupInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${inventoryGroupInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${inventoryGroupInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryGroupDetailed/show.gsp	(revision 875)
@@ -0,0 +1,76 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryGroupInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryGroupInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryGroupInstance, field:'description')}</td>
+                            
+                        </tr>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryGroupInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Items:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${inventoryGroupInstance.inventoryItems}">
+                                    <li><g:link controller="inventoryItemDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${inventoryGroupInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/create.gsp	(revision 875)
@@ -0,0 +1,260 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryItem</title>    
+        <nav:resources override="true"/>     
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${inventoryItemInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryItemInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Inventory Item</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:inventoryItemInstance,field:'name')}"/>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.name" />
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'description','errors')}">
+                                    <textarea rows="5" cols="40" name="description">${fieldValue(bean:inventoryItemInstance, field:'description')}</textarea>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.description" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:inventoryItemInstance, field:'comment')}</textarea>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.comment" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="unitOfMeasure">Unit Of Measure:</label>
+                                </td>
+                                <td valign="top">
+                                    <g:select optionKey="id"
+                                                        from="${UnitOfMeasure.findAllByIsActive(true)}"
+                                                        name="unitOfMeasure.id"
+                                                        value="${inventoryItemInstance?.unitOfMeasure?.id}" >
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.unit.of.measure" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="inventoryLocation">Inventory Location:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'inventoryLocation','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ InventoryLocation.findAllByIsActive(true).sort { p1, p2 -> p1.toString().compareToIgnoreCase(p2.toString()) } }"
+                                                        name="inventoryLocation.id" value="${inventoryItemInstance?.inventoryLocation?.id}"
+                                                        optionValue="${{it.name+ ' in ' + it.inventoryStore}}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]" >
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.inventory.location" />
+
+                                <p><g:link controller="inventoryLocationDetailed" action="create">+Add Location</g:link></p>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="inventoryGroup">Inventory Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'inventoryGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${InventoryGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="inventoryGroup.id"
+                                                        value="${inventoryItemInstance?.inventoryGroup?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]" >
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.inventory.group" />
+                                <p><g:link controller="inventoryGroupDetailed" action="create">+Add Group</g:link></p>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="inventoryType">Inventory Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'inventoryType','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${InventoryType.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="inventoryType.id"
+                                                        value="${inventoryItemInstance?.inventoryType?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]" >
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.inventory.type" />
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Reorder Details</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="enableReorderListing">Enable Reorder Listing:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'enableReorderListing','errors')}">
+                                    <g:checkBox name="enableReorderListing" value="${inventoryItemInstance?.enableReorderListing}" ></g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.enable.reorder.listing" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="reorderPoint">Reorder Point:</label>
+                                </td>
+                                <td valign="top">
+                                    <input class="medium ${hasErrors(bean:inventoryItemInstance,field:'reorderPoint','errors')}"
+                                                    type="text" id="reorderPoint" name="reorderPoint"
+                                                    value="${fieldValue(bean:inventoryItemInstance,field:'reorderPoint')}" />
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.reorder.point" />
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="reorderQuantity">Reorder Quantity:</label>
+                                </td>
+                                <td valign="top">
+                                    <input class="medium ${hasErrors(bean:inventoryItemInstance,field:'reorderQuantity','errors')}"
+                                                type="text" id="reorderQuantity" name="reorderQuantity"
+                                                value="${fieldValue(bean:inventoryItemInstance,field:'reorderQuantity')}" />
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.reorder.quantity" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="estimatedUnitPriceAmount">Estimated Unit Price:</label>
+                                </td>
+                                <td valign="top">
+                                    <input  class="medium ${hasErrors(bean:inventoryItemInstance,field:'estimatedUnitPriceAmount','errors')}"
+                                                    type="text" id="estimatedUnitPriceAmount" name="estimatedUnitPriceAmount"
+                                                    value="${fieldValue(bean:inventoryItemInstance,field:'estimatedUnitPriceAmount')}" />
+                                    <g:currencySelect name="estimatedUnitPriceCurrency"
+                                                                        value="${inventoryItemInstance?.estimatedUnitPriceCurrency}"
+                                                                        from="${grailsApplication.config.currencyList}">
+                                    </g:currencySelect>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.estimated.unit.price.amount" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="suppliersPartNumber">Suppliers Part Number:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'suppliersPartNumber','errors')}">
+                                    <input type="text" id="suppliersPartNumber" maxlength="50" name="suppliersPartNumber" value="${fieldValue(bean:inventoryItemInstance,field:'suppliersPartNumber')}"/>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.suppliers.part.number" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="preferredSupplier">Preferred Supplier:</label>
+                                </td>
+                                <td valign="top">
+                                    <g:select optionKey="id"
+                                                        from="${suppliers}"
+                                                        name="preferredSupplier.id"
+                                                        value="${inventoryItemInstance.preferredSupplier?.id}"
+                                                        noSelection="['null':'--None--']">
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.preferred.supplier" />
+                                    <p><g:link controller="supplierDetailed" action="create">+Add Supplier</g:link></p>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="alternateSuppliers">Alternate Suppliers:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'alternateSuppliers','errors')}">
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.alternate.suppliers" />
+                                    <custom:checkBoxList name="alternateSuppliers"
+                                                                    from="${suppliers}"
+                                                                    value="${inventoryItemInstance?.alternateSuppliers?.collect{it.id}}"
+                                                                    optionKey="id"
+                                                                    linkController="supplierDetailed"
+                                                                    linkAction="show"/>
+                                    <g:link controller="supplierDetailed" action="create">+Add Supplier</g:link>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Spare For</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="spareFor">Assets:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'spareFor','errors')}">
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.spare.for" />
+                                    <custom:checkBoxList name="spareFor"
+                                                                    from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                                    value="${inventoryItemInstance?.spareFor?.collect{it.id}}"
+                                                                    optionKey="id"
+                                                                    sortBy="name"
+                                                                    linkController="assetDetailed"
+                                                                    linkAction="show"/>
+                                    <g:link controller="assetDetailed" action="create">+Add Asset</g:link>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,298 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit InventoryItem</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${inventoryItemInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryItemInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${inventoryItemInstance?.id}" />
+                <input type="hidden" name="version" value="${inventoryItemInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label>Inventory Item</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'name','errors')}">
+                                    <input type="text"
+                                                class="description"
+                                                maxlength="50"
+                                                id="name"
+                                                name="name"
+                                                value="${fieldValue(bean:inventoryItemInstance,field:'name')}"/>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.name" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">Picture:</td>
+                                <td valign="top" class="value">
+                                    <g:if test="${inventoryItemInstance.picture}" >
+                                        <span class='gallery'>
+                                            <wa:pictureLightboxAnchor picture="${inventoryItemInstance.picture}" size="${Image.Small}" lightboxSize="${Image.Large}" target="_blank" title="Show Original" />
+                                        </span>
+                                        <br />
+                                        <g:link controller="pictureDetailed" action="edit" id="${inventoryItemInstance.picture.id}" >
+                                            Edit Picture
+                                        </g:link>
+                                    </g:if>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'description','errors')}">
+                                    <textarea rows="5" cols="40" name="description">${fieldValue(bean:inventoryItemInstance, field:'description')}</textarea>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.description" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:inventoryItemInstance, field:'comment')}</textarea>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.comment" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="unitsInStock">In Stock:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    ${inventoryItemInstance.unitsInStock} ${inventoryItemInstance.unitOfMeasure.encodeAsHTML()}
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.units.in.stock" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="inventoryLocation">Location:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'inventoryLocation','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ InventoryLocation.findAllByIsActive(true).sort { p1, p2 -> p1.toString().compareToIgnoreCase(p2.toString()) } }"
+                                                        name="inventoryLocation.id"
+                                                        value="${inventoryItemInstance?.inventoryLocation?.id}"
+                                                        optionValue="${{it.name+ ' in ' + it.inventoryStore}}">
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.inventory.location" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="inventoryGroup">Inventory Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'inventoryGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${InventoryGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="inventoryGroup.id"
+                                                        value="${inventoryItemInstance?.inventoryGroup?.id}" >
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.inventory.group" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="inventoryType">Inventory Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'inventoryType','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${InventoryType.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="inventoryType.id"
+                                                        value="${inventoryItemInstance?.inventoryType?.id}" >
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.inventory.type" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Reorder Details</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="isActive">Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryItemInstance?.isActive}" ></g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.is.active" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="isObsolete">Obsolete:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'isObsolete','errors')}">
+                                    <g:checkBox name="isObsolete" value="${inventoryItemInstance?.isObsolete}" ></g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.is.obsolete" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="enableReorderListing">Enable Reorder Listing:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'enableReorderListing','errors')}">
+                                    <g:checkBox name="enableReorderListing" value="${inventoryItemInstance?.enableReorderListing}" ></g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.enable.reorder.listing" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="reorderPoint">Reorder Point:</label>
+                                </td>
+                                <td valign="top">
+                                    <input  class="medium ${hasErrors(bean:inventoryItemInstance,field:'reorderPoint','errors')}"
+                                                    type="text" id="reorderPoint" name="reorderPoint"
+                                                    value="${fieldValue(bean:inventoryItemInstance,field:'reorderPoint')}" />
+                                    ${inventoryItemInstance.unitOfMeasure.encodeAsHTML()}
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.reorder.point" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="reorderQuantity">Reorder Quantity:</label>
+                                </td>
+                                <td valign="top">
+                                    <input class="medium ${hasErrors(bean:inventoryItemInstance,field:'reorderQuantity','errors')}"
+                                                type="text" id="reorderQuantity" name="reorderQuantity"
+                                                value="${fieldValue(bean:inventoryItemInstance,field:'reorderQuantity')}" />
+                                     ${inventoryItemInstance.unitOfMeasure.encodeAsHTML()}
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.reorder.quantity" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="estimatedUnitPriceAmount">Estimated Unit Price:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input  class="medium ${hasErrors(bean:inventoryItemInstance,field:'estimatedUnitPriceAmount','errors')}"
+                                                    type="text" id="estimatedUnitPriceAmount" name="estimatedUnitPriceAmount"
+                                                    value="${inventoryItemInstance.estimatedUnitPriceAmount}" />
+                                    <g:currencySelect name="estimatedUnitPriceCurrency"
+                                                                        value="${inventoryItemInstance?.estimatedUnitPriceCurrency}"
+                                                                        from="${grailsApplication.config.currencyList}">
+                                    </g:currencySelect>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.estimated.unit.price.amount" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="suppliersPartNumber">Suppliers Part Number:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'suppliersPartNumber','errors')}">
+                                    <input type="text" id="suppliersPartNumber" maxlength="50" name="suppliersPartNumber" value="${fieldValue(bean:inventoryItemInstance,field:'suppliersPartNumber')}"/>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.suppliers.part.number" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="preferredSupplier">Preferred Supplier:</label>
+                                </td>
+                                <td valign="top">
+                                    <g:select optionKey="id"
+                                                    from="${suppliers}"
+                                                    name="preferredSupplier.id"
+                                                    value="${inventoryItemInstance.preferredSupplier?.id}"
+                                                    noSelection="['null':'--None--']">
+                                    </g:select>
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.preferred.supplier" />
+                                    <p><g:link controller="supplierDetailed" action="create">+Add Supplier</g:link></p>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="alternateSuppliers">Alternate Suppliers:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'alternateSuppliers','errors')}">
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.alternate.suppliers" />
+                                    <custom:checkBoxList name="alternateSuppliers"
+                                                                    from="${suppliers}"
+                                                                    value="${inventoryItemInstance?.alternateSuppliers?.collect{it.id}}"
+                                                                    optionKey="id"
+                                                                    linkController="supplierDetailed"
+                                                                    linkAction="show"/>
+                                    <g:link controller="supplierDetailed" action="create">+Add Supplier</g:link>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupHeader">
+                                    <label for="name">Spare For</label>
+                                </td>
+                                <td valign="top" class="value">
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="groupName">
+                                    <label for="spareFor">Assets:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'spareFor','errors')}">
+                                    <g:helpBalloon class="helpballoon" code="inventory.item.spare.for" />
+                                    <custom:checkBoxList name="spareFor"
+                                                                    from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                                    value="${inventoryItemInstance?.spareFor?.collect{it.id}}"
+                                                                    optionKey="id"
+                                                                    sortBy="name"
+                                                                    linkController="assetDetailed"
+                                                                    linkAction="show"/>
+                                    <g:link controller="assetDetailed" action="create">+Add Asset</g:link>
+                                </td>
+                            </tr>
+
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventory.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventory.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventory.gsp	(revision 875)
@@ -0,0 +1,35 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Import Inventory</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Import Inventory</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:uploadForm action="importInventorySave" onsubmit="return Lightbox.loading();">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="file">File:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input type="file" id="file" name="file" size="40"/>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:uploadForm>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventoryItemPictures.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventoryItemPictures.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventoryItemPictures.gsp	(revision 875)
@@ -0,0 +1,36 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Import Inventory</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Import Inventory Pictures</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:uploadForm action="importInventoryItemPicturesSave" onsubmit="return Lightbox.loading();">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="file">File:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input type="file" id="file" name="file" size="40"/>
+                                    <g:helpBalloon code="inventoryItemPictures.import" />
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:uploadForm>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventoryItemPurchases.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventoryItemPurchases.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/importInventoryItemPurchases.gsp	(revision 875)
@@ -0,0 +1,35 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Import Inventory Item Purchases</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Import Inventory Purchases</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:uploadForm action="importInventoryItemPurchasesSave" onsubmit="return Lightbox.loading();">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="file">File:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input type="file" id="file" name="file" size="40"/>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:uploadForm>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/reorder.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/reorder.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/reorder.gsp	(revision 875)
@@ -0,0 +1,309 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>InventoryItem Reorder</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+        <filterpane:includes />
+        <export:resource />
+    </head>
+    <body onload="if(document.textSearchForm) {document.textSearchForm.searchText.focus();}">
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <div class="textSearchWrapper">
+                <div class="textSearchInput">
+
+                    <g:form method="post" id="textSearchForm" name="textSearchForm" >
+                        <g:hiddenField name="newSearch" value="true" />
+
+                            <span> <!--Prevent IE inheriting margin-->
+
+                                <table>
+                                    <tr>
+                                        <td>
+                                            <label for="selectedGroups">
+                                                Group:
+                                            </label>
+                                        </td>
+                                        <td>
+                                            <custom:checkBoxList name="selectedGroups"
+                                                                            from="${inventoryGroups}"
+                                                                            value="${params.selectedGroups}"
+                                                                            optionKey="id"
+                                                                            sortBy="name"
+                                                                            height="120px"/>
+                                        </td>
+                                    </tr>
+                                    <tr>
+                                        <td>
+                                            <label for="selectedSupplier">
+                                                Supplier:
+                                            </label>
+                                        </td>
+                                        <td>
+                                            <g:select optionKey="id"
+                                                                from="${suppliers}"
+                                                                name="selectedSupplier"
+                                                                value="${params.selectedSupplier}"
+                                                                noSelection="['null':'--None--']">
+                                            </g:select>
+                                        </td>
+                                    </tr>
+                                    <tr>
+                                        <td>
+                                        </td>
+                                        <td>
+                                            <g:checkBox name="includeAlternateSuppliers" value="${params.includeAlternateSuppliers}" >
+                                            </g:checkBox>
+                                            <label for="includeAlternateSuppliers">
+                                                Include alternate suppliers
+                                            </label>
+                                        </td>
+                                    </tr>
+                                    <tr>
+                                        <td>
+                                        </td>
+                                        <td>
+                                            <g:checkBox name="includeReorderListingDisabled" value="${params.includeReorderListingDisabled}" >
+                                            </g:checkBox>
+                                            <label for="includeReorderListingDisabled">
+                                                Include reorder listing disabled
+                                            </label>
+                                        </td>
+                                    </tr>
+                                    <tr>
+                                        <td>
+                                        </td>
+                                        <td>
+                                            <g:checkBox name="includeOnBackOrder" value="${params.includeOnBackOrder}" >
+                                            </g:checkBox>
+                                            <label for="includeOnBackOrder">
+                                                Include items ordered in last 30 days.
+                                            </label>
+                                        </td>
+                                    </tr>
+                                </table>
+
+                                <div class="paginateButtons">
+                                    <span class="buttons">
+                                        <g:actionSubmit class="search" value="Search" action="reorder" />
+                                    </span>
+                                    <div class="paginateButtons">
+                                        Results: ${inventoryItemInstanceList.size()} / ${inventoryItemInstanceTotal}
+                                    </div>
+                                </div><!--paginateButtons-->
+                            </span> <!--Prevent IE inheriting margin-->
+
+                    </g:form>
+
+                </div><!--textSearchInput-->
+
+                <div class="textSearchRightFloat">
+                    <div class="paginateButtons">
+                        <span class="searchButtons">
+                            <a href='' onclick="showElement('searchPane'); return false;">Quick</a>
+                        </span>
+                        <br />
+                        <br />
+                    </div>
+
+                    <jsUtil:toggleControl toggleId="options"
+                                                            imageId="optionsImg"
+                                                            closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                            openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                            text="${g.message(code: 'default.options.text')}"
+                                                            />
+                </div><!--textSearchRightFloat-->
+            </div><!--textSearchWrapper-->
+
+            <div id="options" style="display:none; clear:both;">
+                <g:form method="post" action="setReorderSearchParamsMax" >
+                    <g:hiddenField name="params" value="${filterParams}" />
+                    <div class="dialog">
+                        <table>
+                            <tbody>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Results per page:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <input type="text" maxlength="4" id="description" name="newMax" value="${params.max}"/>
+
+                                        <span class="buttons">
+                                            <g:actionSubmit action="setReorderSearchParamsMax" class="go" value="Update" />
+                                        </span>
+                                    </td>
+                                </tr>
+
+                            </tbody>
+                        </table>
+                    </div>
+                </g:form>
+                <export:formats  params="${filterParams}" formats="['csv', 'excel', 'pdf', 'rtf']"/>
+            </div>
+
+            <br />
+
+            <g:if test="${inventoryItemInstanceList.size() > 2}">
+                <g:if test="${inventoryItemInstanceTotal > inventoryItemInstanceList.size()}">
+                    <div class="paginateButtons">
+                        <g:paginate action="reorder" total="${inventoryItemInstanceTotal}" params="${filterParams}" />
+                    </div>
+                </g:if>
+            </g:if>
+
+            <g:if test="${inventoryItemInstanceList.size() > 0}">
+                <div class="list">
+                    <table>
+                        <thead>
+                            <tr>
+
+                                <th>Picture</th>
+                                <th>Description</th>
+                            
+                                <g:sortableColumn property="inventoryGroup" title="Group" params="${filterParams}" />
+                            
+                                <g:sortableColumn property="unitsInStock" title="In Stock" params="${filterParams}" />
+
+                                <th></th>
+                            
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <g:each in="${inventoryItemInstanceList}" status="i" var="inventoryItemInstance">
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}" />
+
+                                <td class='notClickable'>
+                                    <g:if test="${inventoryItemInstance.picture}" >
+                                        <wa:pictureLightboxAnchor picture="${inventoryItemInstance.picture}"
+                                                                                            size="${Image.Small}"
+                                                                                            lightboxSize="${Image.Large}"
+                                                                                            target="_blank"
+                                                                                            title="Show Original" />
+                                    </g:if>
+                                </td>
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemDetailed/show/${inventoryItemInstance.id}"' >
+                                    <b>${fieldValue(bean:inventoryItemInstance, field:'name')}</b><br />
+                                    ${fieldValue(bean:inventoryItemInstance, field:'description')}
+                                    <br />
+                                    <br />
+                                    Comment:<br />
+                                    ${inventoryItemInstance.comment?.encodeAsHTML()}
+                                    <br />
+                                    <br />
+                                    Reorder Point: ${fieldValue(bean:inventoryItemInstance, field:'reorderPoint')}
+                                    ${fieldValue(bean:inventoryItemInstance, field:'unitOfMeasure')}
+                                    <br />
+                                    P.Supplier: ${fieldValue(bean:inventoryItemInstance, field:'preferredSupplier')}
+                                    <br />
+                                    Spare For: ${inventoryItemInstance.spareFor.join(', ').encodeAsHTML()}
+                                </td>
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemDetailed/show/${inventoryItemInstance.id}"' >
+                                    ${fieldValue(bean:inventoryItemInstance, field:'inventoryGroup')}
+                                </td>
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemDetailed/show/${inventoryItemInstance.id}"' >
+                                    ${fieldValue(bean:inventoryItemInstance, field:'unitsInStock')}
+                                    ${fieldValue(bean:inventoryItemInstance, field:'unitOfMeasure')}
+                                </td>
+
+                                <td class="notClickable">
+                                    <g:link action="show" id="${inventoryItemInstance.id}">
+                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                    </g:link>
+                                </td>
+                            
+                            </tr>
+                        </g:each>
+                        </tbody>
+                    </table>
+                </div>
+            </g:if>
+            <div class="paginateButtons">
+                <g:paginate action="reorder" total="${inventoryItemInstanceTotal}" params="${filterParams}" />
+            </div>
+
+        </div> <!-- end body div -->
+
+        <!-- Start Search Pane -->
+        <div class="overlayPane" id="searchPane" style="display:none;">
+            <h2>Quick Search</h2>
+
+            <g:form method="post" id="searchForm" name="searchForm" >
+                <g:hiddenField name="newTextSearch" value="true" />
+
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Inventory:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <g:link controller="inventoryItemDetailed"
+                                                action="reorder"
+                                                params="[quickSearch: 'all']">
+                                                <g:message code="default.all.text" />
+                                </g:link>
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="reorder"
+                                                params="[quickSearch: 'inventoryBelowReorder']">
+                                                <g:message code="inventoryItem.search.text.below.reorder" />
+                                </g:link> - <g:message code="inventoryItem.search.text.below.reorder.description" />
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="reorder"
+                                                params="[quickSearch: 'inventoryBelowReorderAll']">
+                                                <g:message code="inventoryItem.search.text.below.reorder.all" />
+                                </g:link> - <g:message code="inventoryItem.search.text.below.reorder.all.description" />
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="reorder"
+                                                params="[quickSearch: 'recentlyUsed', daysBack: '14']">
+                                                <g:message code="inventoryItem.search.text.recently.used" />
+                                </g:link> - <g:message code="inventoryItem.search.text.recently.used.description" args="[14]"/>
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="reorder"
+                                                params="[quickSearch: 'recentlyUsed', daysBack: '30']">
+                                                <g:message code="inventoryItem.search.text.recently.used" />
+                                </g:link> - <g:message code="inventoryItem.search.text.recently.used.description" args="[30]"/>
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Links:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <g:link controller="inventoryItemPurchaseDetailed"
+                                                action="search">
+                                                Purchases
+                                </g:link>
+                            </td>
+                        </tr>
+
+                    </tbody>
+                </table>
+
+                <div class="buttons">
+                    <span class="button">
+                        <g:actionSubmit class="cancel" value="${g.message(code:'fp.tag.filterPane.button.cancel.text', default:'Cancel')}" onclick="return hideElement('searchPane');" />
+                    </span>
+                </div>
+            </g:form>
+        </div> <!-- end search pane -->
+
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/search.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/search.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/search.gsp	(revision 875)
@@ -0,0 +1,327 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>InventoryItem Search</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+        <filterpane:includes />
+        <export:resource />
+    </head>
+    <body onload="if(document.textSearchForm) {document.textSearchForm.searchText.focus();}">
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <div class="textSearchWrapper">
+                <div class="textSearchInput">
+
+                    <filterpane:isFiltered >
+                        <filterpane:currentCriteria domainBean="InventoryItem"
+                                                action="search"
+                                                dateFormat="EEE, dd-MMM-yyyy"
+                                                removeImgDir="images"
+                                                removeImgFile="bullet_delete.png"
+                                                title="Advanced Search"/>
+                        <div class="paginateButtons">
+                            Results: ${inventoryItemInstanceList.size()} / ${inventoryItemInstanceTotal}
+                        </div>
+                    </filterpane:isFiltered >
+
+                    <filterpane:isNotFiltered >
+                        <g:form method="post" id="textSearchForm" name="textSearchForm" >
+                            <g:hiddenField name="newTextSearch" value="true" />
+
+                                <span> <!--Prevent IE inheriting margin-->
+                                    <g:textField style="width:450px;" maxlength="75" id="searchText" name="searchText" value="${filterParams.searchText}" />
+                                    <g:helpBalloon code="inventoryItem.search.searchText" />
+
+                                    <g:if test="${params.searchName || params.searchDescription || params.searchComment || params.searchLocation || params.searchGroup || params.searchSpareFor}" >
+                                        <div id="limitSearch" class="textSearchSelect">
+                                    </g:if>
+                                    <g:else>
+                                        <div id="limitSearch" class="textSearchSelect" style="display:none;">
+                                    </g:else>
+                                            Limit Search:
+                                            <br />
+                                            <g:checkBox name="searchName" value="${params.searchName}" ></g:checkBox>
+                                            <label for="searchName">Name</label>
+                                            <g:checkBox name="searchDescription" value="${params.searchDescription}" ></g:checkBox>
+                                            <label for="searchDescription">Description</label>
+                                            <g:checkBox name="searchComment" value="${params.searchComment}" ></g:checkBox>
+                                            <label for="searchComment">Comment</label>
+                                            <g:checkBox name="searchLocation" value="${params.searchLocation}" ></g:checkBox>
+                                            <label for="searchLocation">Location</label>
+                                            <g:checkBox name="searchGroup" value="${params.searchGroup}" ></g:checkBox>
+                                            <label for="searchGroup">Group</label>
+                                            <br />
+                                            <g:checkBox name="searchSpareFor" value="${params.searchSpareFor}" ></g:checkBox>
+                                            <label for="searchSpareFor">Spare For (Asset: Name, Description and Comment).</label>
+                                        </div>
+
+                                    <div class="paginateButtons">
+                                        <span class="buttons">
+                                            <g:actionSubmit class="search" value="Search" action="search" />
+                                        </span>
+                                        <span class="buttons" style="margin-left: 5px;">
+                                            <g:actionSubmit class="complete" value="Select" action="search" onclick="toggleWithEffectUtil('limitSearch'); return false;"/>
+                                        </span>
+                                        <div class="paginateButtons">
+                                            Results: ${inventoryItemInstanceList.size()} / ${inventoryItemInstanceTotal}
+                                        </div>
+                                    </div><!--paginateButtons-->
+                                </span> <!--Prevent IE inheriting margin-->
+
+                        </g:form>
+                    </filterpane:isNotFiltered >
+
+                </div><!--textSearchInput-->
+
+                <div class="textSearchRightFloat">
+                    <div class="paginateButtons">
+                        <span class="searchButtons">
+                            <a href='' onclick="showElement('searchPane'); return false;">Quick</a>
+                        </span>
+                        <br />
+                        <br />
+                        <span class="searchButtons">
+                            <filterpane:filterButton text="Advanced" appliedText="Advanced" />
+                        </span>
+                    </div>
+
+                    <jsUtil:toggleControl toggleId="options"
+                                                            imageId="optionsImg"
+                                                            closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                            openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                            text="${g.message(code: 'default.options.text')}"
+                                                            />
+                </div><!--textSearchRightFloat-->
+            </div><!--textSearchWrapper-->
+
+            <div id="options" style="display:none; clear:both;">
+                <g:form method="post" action="setSearchParamsMax" >
+                    <g:hiddenField name="params" value="${filterParams}" />
+                    <div class="dialog">
+                        <table>
+                            <tbody>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Results per page:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <input type="text" maxlength="4" id="description" name="newMax" value="${params.max}"/>
+
+                                        <span class="buttons">
+                                            <g:actionSubmit action="setSearchParamsMax" class="go" value="Update" />
+                                        </span>
+                                    </td>
+                                </tr>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Inventory:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:link action="exportInventory">
+                                            Export
+                                        </g:link>
+                                        /
+                                        <g:link action="exportInventoryTemplate">
+                                            Template
+                                        </g:link>
+                                        /
+                                        <g:link action="exportInventoryExample">
+                                            Example
+                                        </g:link>
+                                        /
+                                        <g:link action="importInventory">
+                                            Import Inventory
+                                        </g:link>
+                                        /
+                                        <g:link action="importInventoryItemPurchases">
+                                            Import Purchases
+                                        </g:link>
+                                        /
+                                        <g:link action="importInventoryItemPictures">
+                                            Import Pictures
+                                        </g:link>
+                                    </td>
+                                </tr>
+
+                            </tbody>
+                        </table>
+                    </div>
+                </g:form>
+                <export:formats  params="${filterParams}" formats="['csv', 'excel', 'pdf', 'rtf']"/>
+            </div>
+
+            <br />
+
+            <g:if test="${inventoryItemInstanceList.size() > 2}">
+                <g:if test="${inventoryItemInstanceTotal > inventoryItemInstanceList.size()}">
+                    <div class="paginateButtons">
+                        <g:paginate action="search" total="${inventoryItemInstanceTotal}" params="${filterParams}" />
+                    </div>
+                </g:if>
+            </g:if>
+
+            <g:if test="${inventoryItemInstanceList.size() > 0}">
+                <div class="list">
+                    <table>
+                        <thead>
+                            <tr>
+
+                                <th>Picture</th>
+                                <th>Description</th>
+                            
+                                <g:sortableColumn property="inventoryGroup" title="Group" params="${filterParams}" />
+                            
+                                <g:sortableColumn property="unitsInStock" title="In Stock" params="${filterParams}" />
+
+                                <th></th>
+                            
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <g:each in="${inventoryItemInstanceList}" status="i" var="inventoryItemInstance">
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}" />
+
+                                <td class='notClickable'>
+                                    <g:if test="${inventoryItemInstance.picture}" >
+                                        <wa:pictureLightboxAnchor picture="${inventoryItemInstance.picture}"
+                                                                                            size="${Image.Small}"
+                                                                                            lightboxSize="${Image.Large}"
+                                                                                            target="_blank"
+                                                                                            title="Show Original" />
+                                    </g:if>
+                                </td>
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemDetailed/show/${inventoryItemInstance.id}"' >
+                                    <b>${fieldValue(bean:inventoryItemInstance, field:'name')}</b><br />
+                                    ${fieldValue(bean:inventoryItemInstance, field:'description')}
+                                    <br />
+                                    <br />
+                                    Location: ${inventoryItemInstance.inventoryLocation?.encodeAsHTML()}
+                                    in ${inventoryItemInstance.inventoryLocation?.inventoryStore.encodeAsHTML()}<br />
+                                </td>
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemDetailed/show/${inventoryItemInstance.id}"' >
+                                    ${fieldValue(bean:inventoryItemInstance, field:'inventoryGroup')}
+                                </td>
+                            
+                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemDetailed/show/${inventoryItemInstance.id}"' >
+                                    ${fieldValue(bean:inventoryItemInstance, field:'unitsInStock')}
+                                    ${fieldValue(bean:inventoryItemInstance, field:'unitOfMeasure')}
+                                </td>
+
+                                <td class="notClickable">
+                                    <g:link action="show" id="${inventoryItemInstance.id}">
+                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                    </g:link>
+                                </td>
+                            
+                            </tr>
+                        </g:each>
+                        </tbody>
+                    </table>
+                </div>
+            </g:if>
+            <div class="paginateButtons">
+                <g:paginate action="search" total="${inventoryItemInstanceTotal}" params="${filterParams}" />
+            </div>
+
+            <filterpane:filterPane domainBean="InventoryItem"
+                                    title="Advanced Search"
+                                    action="search"
+                                    class="overlayPane"
+                                    excludeProperties="estimatedUnitPriceCurrency"
+                                    associatedProperties="inventoryLocation.name,
+                                                                            spareFor.name"
+                                    filterPropertyValues="${['inventoryLocation.name':[values: associatedPropertyValues.inventoryLocationList],
+                                                                                'spareFor.name':[values: associatedPropertyValues.assetList],
+                                                                                'preferredSupplier.name':[values: associatedPropertyValues.supplierList]
+                                                                                ]}"/>
+        </div> <!-- end body div -->
+
+        <!-- Start Search Pane -->
+        <div class="overlayPane" id="searchPane" style="display:none;">
+            <h2>Quick Search</h2>
+
+            <g:form method="post" id="searchForm" name="searchForm" >
+                <g:hiddenField name="newTextSearch" value="true" />
+
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Inventory:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'all']">
+                                                <g:message code="default.all.text" />
+                                </g:link>
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'inventoryBelowReorder']">
+                                                <g:message code="inventoryItem.search.text.below.reorder" />
+                                </g:link> - <g:message code="inventoryItem.search.text.below.reorder.description" />
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'inventoryBelowReorderAll']">
+                                                <g:message code="inventoryItem.search.text.below.reorder.all" />
+                                </g:link> - <g:message code="inventoryItem.search.text.below.reorder.all.description" />
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'recentlyUsed', daysBack: '14']">
+                                                <g:message code="inventoryItem.search.text.recently.used" />
+                                </g:link> - <g:message code="inventoryItem.search.text.recently.used.description" args="[14]"/>
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'recentlyUsed', daysBack: '30']">
+                                                <g:message code="inventoryItem.search.text.recently.used" />
+                                </g:link> - <g:message code="inventoryItem.search.text.recently.used.description" args="[30]"/>
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Links:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <g:link controller="inventoryItemPurchaseDetailed"
+                                                action="search">
+                                                Purchases
+                                </g:link>
+                                <br />
+                                <g:link controller="inventoryItemDetailed"
+                                                action="reorder">
+                                                Reorder
+                                </g:link>
+                            </td>
+                        </tr>
+
+                    </tbody>
+                </table>
+
+                <div class="buttons">
+                    <span class="button">
+                        <g:actionSubmit class="cancel" value="${g.message(code:'fp.tag.filterPane.button.cancel.text', default:'Cancel')}" onclick="return hideElement('searchPane');" />
+                    </span>
+                </div>
+            </g:form>
+        </div> <!-- end search pane -->
+
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemDetailed/show.gsp	(revision 875)
@@ -0,0 +1,565 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryItem</title>
+        <nav:resources override="true"/>
+        <resource:tabView skin="tabviewCustom" />
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:if test="${inventoryItemInstance.isObsolete || !inventoryItemInstance.isActive}" >
+                <div class="errors">
+                    <ul>
+                        <g:if test="${inventoryItemInstance.isObsolete}" >
+                            <li><g:message code="inventory.item.is.obsolete.message" /><li>
+                        </g:if>
+                        <g:if test="${!inventoryItemInstance.isActive}" >
+                            <li><g:message code="inventory.item.not.active.message" /><li>
+                        </g:if>
+                    </ul>
+                </div>
+            </g:if>
+            <g:if test="${!inventoryItemInstance.enableReorderListing}" >
+                <div class="message">
+                    <g:message code="inventory.item.reorder.listing.disabled" />
+                </div>
+            </g:if>
+            <g:hasErrors bean="${inventoryMovementInstance}">
+                <div class="errors">
+                    <g:renderErrors bean="${inventoryMovementInstance}" as="list" />
+                </div>
+            </g:hasErrors>
+
+            <g:hasErrors bean="${inventoryItemInstance}">
+                <div class="errors">
+                    <g:renderErrors bean="${inventoryItemInstance}" as="list" />
+                </div>
+            </g:hasErrors>
+
+            <div class="tabHeader">
+                <h1>
+                    ${inventoryItemInstance.name}
+                </h1>
+                ${fieldValue(bean:inventoryItemInstance, field:'description')}
+            </div>
+
+            <br/>
+
+            <richui:tabView id="tabView">
+
+                <richui:tabLabels>
+                    <richui:tabLabel selected="${showTab.inventory}" title="Inventory Item" />
+                    <g:if test="${!inventoryMovementList.isEmpty()}">
+                        <richui:tabLabel selected="${showTab.movement}" title="Movement (${inventoryMovementList.size()})" />
+                    </g:if>
+                    <g:else>
+                        <richui:tabLabel selected="${showTab.movement}" title="Movement" />
+                    </g:else>
+                    <g:if test="${!inventoryItemPurchases.isEmpty()}">
+                        <richui:tabLabel selected="${showTab.purchasing}" title="Purchasing (${inventoryItemPurchases.size()})" />
+                    </g:if>
+                    <g:else>
+                        <richui:tabLabel selected="${showTab.purchasing}" title="Purchasing" />
+                    </g:else>
+                </richui:tabLabels>
+
+                <richui:tabContents>
+
+<!-- Start Inventory tab -->
+                    <richui:tabContent>
+
+                        <g:if test="${inventoryMovementInstance}" >
+
+                            <div id="useInventoryItemDiv" style="display:inline"> <!-- inline required for IE -->
+                                <div class="pane_close" >
+                                    <g:remoteLink action="clearUseInventoryItem" update="useInventoryItemDiv">
+                                        <img  src="${resource(dir:'images/skin',file:'cross.png')}" alt="Clear" title="Clear"/>
+                                    </g:remoteLink>
+                                </div>
+                                <g:form controller="inventoryItemDetailed" action="useInventoryItem" method="post" >
+                                    <div class="dialog">
+                                        <table>
+                                            <tbody>
+                                                    <g:hiddenField name="task.id" value="${inventoryMovementInstance.task.id}"/>
+                                                    <g:hiddenField name="inventoryItem.id" value="${inventoryItemInstance.id}"/>
+                                                    <tr class="prop">
+                                                        <td valign="top" class="name">Use on task:</td>
+                                                        <td valign="top" class="value">
+                                                            <g:link controller="taskDetailed" action="show" id="${inventoryMovementInstance.task.id}" >
+                                                                ${Task.get(inventoryMovementInstance.task.id).encodeAsHTML()}
+                                                            </g:link>
+                                                        </td>
+                                                    </tr>
+
+                                                    <tr class="prop">
+                                                        <td valign="top" class="name">
+                                                            <label for="quantity">Quantity:</label>
+                                                        </td>
+                                                        <td valign="top">
+                                                            <input class="medium ${hasErrors(bean:inventoryMovementInstance,field:'quantity','errors')}"
+                                                                        type="text" id="quantity" name="quantity"
+                                                                        value="${fieldValue(bean:inventoryMovementInstance,field:'quantity')}"/>
+                                                            ${inventoryItemInstance.unitOfMeasure?.encodeAsHTML()}
+
+                                                            <span class="buttons">
+                                                                <g:actionSubmit action="useInventoryItem" class="save" value="${InventoryMovementType.read(1)}" />
+                                                            </span>
+
+                                                        </td>
+                                                    </tr>
+
+                                            </tbody>
+                                        </table>
+                                    </div>
+                                </g:form>
+
+                                <br />
+                            </div>
+
+                        </g:if>
+
+                        <div class="dialog">
+                            <table>
+                                <tbody>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Picture:</td>
+                                        <td valign="top" class="value">
+                                            <g:if test="${inventoryItemInstance.picture}" >
+                                                <span class='gallery'><wa:pictureLightboxAnchor picture="${inventoryItemInstance.picture}" size="${Image.Small}" lightboxSize="${Image.Large}" target="_blank" title="Show Original" /></span>
+                                            </g:if>
+                                            <g:else>
+                                                <g:link controller="pictureDetailed"
+                                                                params="['inventoryItem.id':inventoryItemInstance.id]"
+                                                                action="create">
+                                                    Add Picture
+                                                </g:link>
+                                            </g:else>
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Comment:</td>
+
+                                        <td valign="top" class="value">${fieldValue(bean:inventoryItemInstance, field:'comment')}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">In Stock:</td>
+
+                                        <td valign="top" class="value">
+                                            ${fieldValue(bean:inventoryItemInstance, field:'unitsInStock')} ${inventoryItemInstance.unitOfMeasure.encodeAsHTML()}
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Location:</td>
+
+                                        <td valign="top" class="value">
+                                            <g:link controller="inventoryLocationDetailed" action="show" id="${inventoryItemInstance.inventoryLocation?.id}">
+                                                ${inventoryItemInstance.inventoryLocation?.encodeAsHTML()}
+                                            </g:link>
+                                                in ${inventoryItemInstance.inventoryLocation?.inventoryStore.encodeAsHTML()}
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Inventory Group:</td>
+                                        <td valign="top" class="value">${inventoryItemInstance.inventoryGroup?.encodeAsHTML()}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Inventory Type:</td>
+                                        <td valign="top" class="value">${inventoryItemInstance.inventoryType?.encodeAsHTML()}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupHeader">
+                                            <label for="name">Reorder Details</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Active:</td>
+
+                                        <td valign="top" class="value">${fieldValue(bean:inventoryItemInstance, field:'isActive')}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Obsolete:</td>
+                                        <td valign="top" class="value">${fieldValue(bean:inventoryItemInstance, field:'isObsolete')}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Enable Reorder Listing:</td>
+                                        <td valign="top" class="value">${fieldValue(bean:inventoryItemInstance, field:'enableReorderListing')}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Reorder Point:</td>
+                                        <td valign="top" class="value">${fieldValue(bean:inventoryItemInstance, field:'reorderPoint')}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Reorder Quantity:</td>
+                                        <td valign="top" class="value">${fieldValue(bean:inventoryItemInstance, field:'reorderQuantity')}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Estimated Unit Price:</td>
+
+                                        <td valign="top" class="value">
+                                            <g:if test="${inventoryItemInstance.estimatedUnitPriceAmount}">
+                                                ${inventoryItemInstance.estimatedUnitPriceAmount.encodeAsHTML()}
+                                                ${inventoryItemInstance.estimatedUnitPriceCurrency.encodeAsHTML()}
+                                            </g:if>
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Suppliers Part Number:</td>
+                                        <td valign="top" class="value">${fieldValue(bean:inventoryItemInstance, field:'suppliersPartNumber')}</td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Preferred Supplier:</td>
+
+                                        <td  valign="top" style="text-align:left;" class="value">
+                                            <g:link controller="supplierDetailed" action="show" id="${inventoryItemInstance.preferredSupplier?.id}">
+                                                ${inventoryItemInstance.preferredSupplier?.encodeAsHTML()}
+                                            </g:link>
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Alternate Suppliers:</td>
+
+                                        <td  valign="top" style="text-align:left;" class="value">
+                                            <ul>
+                                            <g:each var="s" in="${ inventoryItemInstance.alternateSuppliers.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                                                <li><g:link controller="supplierDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                            </g:each>
+                                            </ul>
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupHeader">
+                                            <label for="name">Spare For</label>
+                                        </td>
+                                        <td valign="top" class="value">
+                                        </td>
+                                    </tr>
+
+                                    <tr class="prop">
+                                        <td valign="top" class="groupName">Assets:</td>
+
+                                        <td  valign="top" style="text-align:left;" class="value">
+                                            <ul>
+                                            <g:each var="s" in="${ inventoryItemInstance.spareFor.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                                                <li><g:link controller="assetDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                            </g:each>
+                                            </ul>
+                                        </td>
+                                    </tr>
+
+                                </tbody>
+                            </table>
+                        </div>
+                        <div class="buttons">
+                            <g:form>
+                                <g:hiddenField name="id" value="${inventoryItemInstance.id}" />
+                                <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                                <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                            </g:form>
+                        </div>
+
+                        <br />
+
+                    </richui:tabContent>
+<!-- End Inventory tab -->
+
+<!-- Start Movement tab -->
+                    <richui:tabContent>
+
+                        <g:if test="${inventoryMovementList.isEmpty()}">
+                            <br />
+                            No Inventory Movements.
+                            <br />
+                            <br />
+
+                            <div class="buttons">
+                                <g:form controller="inventoryMovementDetailed">
+                                    <g:hiddenField name="inventoryItem.id" value="${inventoryItemInstance.id}" />
+                                    <span class="button"><g:actionSubmit action="create" class="add" value="Create" /></span>
+                                </g:form>
+                            </div>
+
+                        </g:if>
+                        <g:else>
+
+                            <div class="list">
+                                <table>
+                                    <thead>
+                                        <tr>
+                                            <th>Quantity</th>
+                                            <th>Movement Type</th>
+                                            <th>Date</th>
+                                            <th>Person</th>
+                                            <th></th>
+                                        </tr>
+                                    </thead>
+                                    <tbody>
+                                        <g:each in="${inventoryMovementList}" status="i" var="movements">
+                                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${movements.id}"'>
+                                                    ${fieldValue(bean:movements, field:'quantity')}
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${movements.id}"'>
+                                                    ${fieldValue(bean:movements, field:'inventoryMovementType')}
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${movements.id}"'>
+                                                    <g:formatDate date="${movements.date}" format="EEE, dd-MMM-yyyy"/>
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${movements.id}"'>
+                                                    ${fieldValue(bean:movements, field:'person')}
+                                                </td>
+
+                                                <td class="notClickable">
+                                                    <g:link controller="inventoryMovementDetailed" action="show" id="${movements.id}">
+                                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                                    </g:link>
+                                                </td>
+
+                                            </tr>
+                                        </g:each>
+                                    </tbody>
+                                </table>
+                            </div>
+
+                            <div class="buttons">
+                                <g:form controller="inventoryMovementDetailed">
+                                    <g:hiddenField name="inventoryItem.id" value="${inventoryItemInstance.id}" />
+                                    <g:if test="${inventoryMovementListTotal > inventoryMovementListMax}">
+                                        Showing ${inventoryMovementListMax} of ${inventoryMovementListTotal}
+                                        <br />
+                                    </g:if>
+                                    <g:else>
+                                        Total ${inventoryMovementListTotal}
+                                        <br />
+                                    </g:else>
+                                    <span class="button"><g:actionSubmit action="listInventoryMovements" class="table" value="List" /></span>
+                                    <span class="button"><g:actionSubmit action="create" class="add" value="Create" /></span>
+                                </g:form>
+                            </div>
+
+                        </g:else>
+
+                    </richui:tabContent>
+<!-- End Movement tab -->
+
+<!-- Start Purchases tab -->
+                    <richui:tabContent>
+
+                        <g:if test="${inventoryItemPurchases.isEmpty()}">
+                            <br />
+                            No Inventory Purchases.
+                            <br />
+                            <br />
+
+                            <div class="buttons">
+                                <!--Fake button to prevent ordering disabled inventory items-->
+                                <g:if test="${inventoryItemInstance.isObsolete || !inventoryItemInstance.isActive}" >
+                                    <g:form controller="inventoryItemDetailed">
+                                        <g:hiddenField name="id" value="${inventoryItemInstance.id}" />
+                                        <span class="button">
+                                            <g:actionSubmit action="show" class="add" value="${g.message(code:'inventory.item.reorder.not.allowed')}" />
+                                        </span>
+                                        <span class="button">
+                                            <input type="button" class="search" value="Search"
+                                                        onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/search"' />
+                                        </span>
+                                    </g:form>
+                                </g:if>
+                                <g:else><!--Real order button.-->
+                                    <g:form controller="inventoryItemPurchaseDetailed">
+                                        <g:hiddenField name="inventoryItem.id" value="${inventoryItemInstance.id}" />
+                                        <span class="button">
+                                            <g:actionSubmit action="create" class="add" value="Order" />
+                                        </span>
+                                        <span class="button">
+                                            <g:actionSubmit action="search" class="search" value="Search" />
+                                        </span>
+                                    </g:form>
+                                </g:else>
+                            </div>
+
+                        </g:if>
+                        <g:else>
+
+                            <div class="list">
+                                <table>
+                                    <thead>
+                                        <tr>
+                                            <g:sortableColumn action="show" property="purchaseOrderNumber"
+                                                                                title="Order #" params="[paginate: 'purchases']"  />
+                                            <g:sortableColumn action="show"  property="date"
+                                                                                title="Date" params="[paginate: 'purchases']" />
+                                            <g:sortableColumn action="show"  property="costCode"
+                                                                                title="Cost Code" params="[paginate: 'purchases']" />
+                                            <g:sortableColumn action="show"  property="quantity"
+                                                                                title="Quantity" params="[paginate: 'purchases']" />
+                                            <g:sortableColumn action="show"  property="orderValueAmount"
+                                                                                title="Order \$" params="[paginate: 'purchases']" />
+                                            <g:sortableColumn action="show"  property="invoiceNumber"
+                                                                                title="Invoice Number" params="[paginate: 'purchases']" />
+                                            <g:sortableColumn action="show"  property="inventoryItemPurchaseType"
+                                                                                title="Type" params="[paginate: 'purchases']" />
+                                            <th>
+                                                <img  src="${resource(dir:'images/skin',file:'database_go_grey.png')}" alt="Show" title="Show" />
+                                            </th>
+                                            <th>
+                                                <img  src="${resource(dir:'images/skin',file:'basket_put_grey.png')}" alt="Receive" title="Receive" />
+                                            </th>
+                                            <th>
+                                                <img  src="${resource(dir:'images/skin',file:'tick_grey.png')}" alt="Approve" title="Approve Payment" />
+                                            </th>
+                                        </tr>
+                                    </thead>
+                                    <tbody>
+                                        <g:each in="${inventoryItemPurchases}" status="i" var="purchase">
+                                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}"'>
+                                                    ${fieldValue(bean:purchase, field:'purchaseOrderNumber')}
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}"'>
+                                                    <g:formatDate date="${purchase.date}" format="EEE, dd-MMM-yyyy"/>
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}"'>
+                                                    ${fieldValue(bean:purchase, field:'costCode')}
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}"'>
+                                                    ${fieldValue(bean:purchase, field:'quantity')}
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}"'>
+                                                    ${fieldValue(bean:purchase, field:'orderValueAmount')}
+                                                    ${fieldValue(bean:purchase, field:'orderValueCurrency')}
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}"'>
+                                                    ${fieldValue(bean:purchase, field:'invoiceNumber')}
+                                                </td>
+                                                <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}"'>
+                                                    ${fieldValue(bean:purchase, field:'inventoryItemPurchaseType')}
+                                                </td>
+                                                <td class="notClickable">
+                                                    <g:link controller="inventoryItemPurchaseDetailed" action="show" id="${purchase.id}">
+                                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" title="Show" />
+                                                    </g:link>
+                                                </td>
+
+                                                <g:if test="${purchase.inventoryItemPurchaseType.id == 1}">
+                                                    <g:if test="${!purchase.receivedComplete}">
+                                                        <td class="notClickable">
+                                                            <g:link controller="inventoryItemPurchaseDetailed" action="receive" params="[id: purchase.id, returnTo: 'inventoryItem']">
+                                                                <img  src="${resource(dir:'images/skin',file:'basket_put.png')}" alt="Receive" title="Receive" />
+                                                            </g:link>
+                                                        </td>
+                                                        <td class="notClickable">
+                                                        </td>
+                                                    </g:if>
+                                                    <g:else>
+                                                        <td class="notClickable">
+                                                        </td>
+                                                        <td class="notClickable">
+                                                        </td>
+                                                    </g:else>
+                                                </g:if>
+                                                <g:elseif test="${(purchase.inventoryItemPurchaseType.id == 2)||(purchase.inventoryItemPurchaseType.id == 3)}">
+                                                    <g:if test="${!purchase.invoicePaymentApproved}">
+                                                        <td class="notClickable">
+                                                        </td>
+                                                        <td class="notClickable">
+                                                            <g:link controller="inventoryItemPurchaseDetailed" action="approveInvoicePayment" params="[id: purchase.id, returnTo: 'inventoryItem']">
+                                                                <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Approve" title="Approve Payment" />
+                                                            </g:link>
+                                                        </td>
+                                                    </g:if>
+                                                    <g:else>
+                                                        <td class="notClickable">
+                                                        </td>
+                                                        <td class="notClickable">
+                                                        </td>
+                                                    </g:else>
+                                                </g:elseif>
+                                                <g:else>
+                                                    <td class="notClickable">
+                                                    </td>
+                                                    <td class="notClickable">
+                                                    </td>
+                                                </g:else>
+
+                                            </tr>
+                                        </g:each>
+                                    </tbody>
+                                </table>
+                            </div>
+
+                            <div class="buttons">
+                                <!--Fake button to prevent ordering disabled inventory items-->
+                                <g:if test="${inventoryItemInstance.isObsolete || !inventoryItemInstance.isActive}" >
+                                    <g:form controller="inventoryItemDetailed">
+                                        <g:hiddenField name="id" value="${inventoryItemInstance.id}" />
+                                        Results: ${inventoryItemPurchases.size()} / ${inventoryItemPurchasesTotal}
+                                        <span class="button">
+                                            <g:actionSubmit action="show" class="add" value="${g.message(code:'inventory.item.reorder.not.allowed')}" />
+                                        </span>
+                                        <span class="button">
+                                            <input type="button" class="search" value="Search"
+                                                        onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/search"' />
+                                        </span>
+                                    </g:form>
+                                </g:if>
+                                <g:else><!--Real order button.-->
+                                    <g:form controller="inventoryItemPurchaseDetailed">
+                                        <g:hiddenField name="inventoryItem.id" value="${inventoryItemInstance.id}" />
+                                        Results: ${inventoryItemPurchases.size()} / ${inventoryItemPurchasesTotal}
+                                        <span class="button">
+                                            <g:actionSubmit action="create" class="add" value="Order" />
+                                        </span>
+                                        <span class="button">
+                                            <g:actionSubmit action="search" class="search" value="Search" />
+                                        </span>
+                                    </g:form>
+                                </g:else>
+                            </div>
+
+                            <div class="paginateButtons">
+                                <g:paginate action="show"
+                                                        id="${inventoryItemInstance?.id}"
+                                                        total="${inventoryItemPurchasesTotal}"
+                                                        params="[paginate: 'purchases']" />
+                            </div>
+
+                        </g:else>
+
+                    </richui:tabContent>
+<!-- End Movement tab -->
+
+                </richui:tabContents>
+            </richui:tabView>
+
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/approveInvoicePayment.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/approveInvoicePayment.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/approveInvoicePayment.gsp	(revision 875)
@@ -0,0 +1,122 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Approve Payment InventoryItemPurchase</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Approve Payment</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${inventoryItemPurchaseInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryItemPurchaseInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="approveInvoicePaymentSave" method="post" >
+                <g:hiddenField name="inventoryItem.id" value="${inventoryItemPurchaseInstance.inventoryItem?.id}" />
+                <g:hiddenField name="receivedId" value="${receivedId}" />
+                <g:hiddenField name="supplier.id" value="${inventoryItemPurchaseInstance.supplier?.id}" />
+                <g:hiddenField name="taskBudgetStatus.id" value="${inventoryItemPurchaseInstance.taskBudgetStatus?.id}" />
+                <g:hiddenField name="returnTo" value="${params.returnTo}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItem">Inventory Item:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:link controller="inventoryItemDetailed"
+                                                    action="show"
+                                                    id="${inventoryItemPurchaseInstance.inventoryItem.id}">
+                                        ${inventoryItemPurchaseInstance.inventoryItem.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="purchaseOrderNumber">Purchase Order #:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    ${inventoryItemPurchaseInstance.purchaseOrderNumber.encodeAsHTML()}
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="costCode">Cost Code:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'costCode','errors')}">
+                                    ${inventoryItemPurchaseInstance.costCode.encodeAsHTML()}
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskBudgetStatus">Budget Status:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'taskBudgetStatus','errors')}">
+                                    ${inventoryItemPurchaseInstance.taskBudgetStatus.encodeAsHTML()}
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="quantity">Invoice #:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'invoiceNumber','errors')}">
+                                    <input type="text" id="invoiceNumber" name="invoiceNumber" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'invoiceNumber')}" />
+                                    <g:helpBalloon code="inventoryItemPurchase.invoice.number" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="quantity">Quantity:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'quantity','errors')}">
+                                    <input type="text" id="quantity" name="quantity" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'quantity')}" />
+                                    ${inventoryItemPurchaseInstance.inventoryItem.unitOfMeasure.encodeAsHTML()}
+                                    <g:helpBalloon code="inventoryItemPurchase.approve.quantity" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="orderValue">Approve Value:</label>
+                                </td>
+                                <td valign="top">
+                                    <input  class="medium ${hasErrors(bean:inventoryItemPurchaseInstance,field:'orderValueAmount','errors')}"
+                                                    type="text" id="orderValueAmount" name="orderValueAmount"
+                                                    value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'orderValueAmount')}" />
+                                    ${inventoryItemPurchaseInstance.orderValueCurrency?.encodeAsHTML()}
+                                    <g:helpBalloon code="inventoryItemPurchase.approve.value" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:inventoryItemPurchaseInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/create.gsp	(revision 875)
@@ -0,0 +1,159 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryItemPurchase</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Order Inventory</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:if test="${!costCodes}" >
+                <div class="errors">
+                    <ul>
+                        <li><g:message code="inventoryItemPurchase.costCodes.not.found" /><li>
+                </div>
+            </g:if>
+            <g:hasErrors bean="${inventoryItemPurchaseInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryItemPurchaseInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <g:hiddenField name="inventoryItem.id" value="${inventoryItemPurchaseInstance?.inventoryItem?.id}" />
+                <g:hiddenField name="returnTo" value="${params.returnTo}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItem">Inventory Item:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:link controller="inventoryItemDetailed"
+                                                    action="show"
+                                                    id="${inventoryItemPurchaseInstance.inventoryItem.id}">
+                                        ${inventoryItemPurchaseInstance.inventoryItem.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="purchaseOrderNumber">Purchase Order #:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'purchaseOrderNumber','errors')}">
+                                    <input type="text" maxlength="50" id="purchaseOrderNumber" name="purchaseOrderNumber" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'purchaseOrderNumber')}"/>
+                                    <g:helpBalloon code="inventoryItemPurchase.purchaseOrderNumber" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="date">Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'date','errors')}">
+                                    <richui:dateChooser name="date" format="dd-MM-yyyy" value="${inventoryItemPurchaseInstance.date}" />
+                                    <g:helpBalloon code="inventoryItemPurchase.order.placed.date" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="costCode">Cost Code:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'costCode','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ costCodes }"
+                                                        name="costCode.id"
+                                                        value="${inventoryItemPurchaseInstance?.costCode?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="inventoryItemPurchase.cost.code" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskBudgetStatus">Budget Status:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'taskBudgetStatus','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ TaskBudgetStatus.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
+                                                        name="taskBudgetStatus.id"
+                                                        value="${inventoryItemPurchaseInstance?.taskBudgetStatus?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="inventoryItemPurchase.task.budget.status" />
+                                </td>
+                            </tr>
+                        
+                             <tr class="prop">
+                                 <td valign="top" class="name">
+                                    <label for="supplier">Supplier:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'supplier','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
+                                                        name="supplier.id"
+                                                        value="${inventoryItemPurchaseInstance?.supplier?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="inventoryItemPurchase.supplier" />
+                                    <p><g:link controller="supplierDetailed" action="create">+Add Supplier</g:link></p>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="quantity">Quantity:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'quantity','errors')}">
+                                    <input type="text" id="quantity" name="quantity" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'quantity')}" />
+                                    ${inventoryItemPurchaseInstance.inventoryItem.unitOfMeasure.encodeAsHTML()}
+                                    <g:helpBalloon code="inventoryItemPurchase.quantity" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="orderValue">Order Value:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input  class="medium ${hasErrors(bean:inventoryItemPurchaseInstance,field:'orderValueAmount','errors')}"
+                                                    type="text" id="orderValueAmount" name="orderValueAmount"
+                                                    value="${inventoryItemPurchaseInstance.orderValueAmount}" />
+                                    <g:currencySelect name="orderValueCurrency"
+                                                                        value="${inventoryItemPurchaseInstance?.orderValueCurrency}"
+                                                                        from="${grailsApplication.config.currencyList}">
+                                    </g:currencySelect>
+                                    <g:helpBalloon code="inventoryItemPurchase.order.value" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:inventoryItemPurchaseInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,229 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit InventoryItemPurchase</title>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit InventoryItemPurchase</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${inventoryItemPurchaseInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryItemPurchaseInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${inventoryItemPurchaseInstance?.id}" />
+                <input type="hidden" name="version" value="${inventoryItemPurchaseInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                    
+                            <tr class="prop">
+                                <td valign="top" class="name">Inventory Item:</td>
+                                
+                                <td valign="top" class="value"><g:link controller="inventoryItemDetailed" action="show" id="${inventoryItemPurchaseInstance?.inventoryItem?.id}">${inventoryItemPurchaseInstance?.inventoryItem?.encodeAsHTML()}</g:link></td>
+                                
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">Purchase Type:</td>
+                                
+                                <td valign="top" class="value">${inventoryItemPurchaseInstance?.inventoryItemPurchaseType?.encodeAsHTML()}</td>
+                                
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="invoiceNumber">Purchase Order #:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'purchaseOrderNumber','errors')}">
+                                    <input type="text" maxlength="50" id="purchaseOrderNumber" name="purchaseOrderNumber" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'purchaseOrderNumber')}"/>
+                                    <g:helpBalloon code="inventoryItemPurchase.purchaseOrderNumber" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="date">Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'date','errors')}">
+                                    <richui:dateChooser name="date" format="dd-MM-yyyy" value="${inventoryItemPurchaseInstance.date}" />
+                                    <g:helpBalloon code="inventoryItemPurchase.order.placed.date" />
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="costCode">Cost Code:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'costCode','errors')}">
+                                    <g:if test="${costCodes}">
+                                        <g:select optionKey="id"
+                                                            from="${ costCodes }"
+                                                            name="costCode.id"
+                                                            value="${inventoryItemPurchaseInstance.costCode?.id}" >
+                                        </g:select>
+                                    </g:if>
+                                    <g:else>
+                                        <g:link controller="costCodeDetailed" action="show" id="${inventoryItemPurchaseInstance?.costCode?.id}">
+                                            ${inventoryItemPurchaseInstance?.costCode?.encodeAsHTML()}
+                                        </g:link>
+                                    </g:else>
+                                    <g:helpBalloon code="inventoryItemPurchase.cost.code" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskBudgetStatus">Budget Status:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'taskBudgetStatus','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ TaskBudgetStatus.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
+                                                        name="taskBudgetStatus.id"
+                                                        value="${inventoryItemPurchaseInstance?.taskBudgetStatus?.id}" >
+                                    </g:select>
+                                    <g:helpBalloon code="inventoryItemPurchase.task.budget.status" />
+                                </td>
+                            </tr>
+                        
+                             <tr class="prop">
+                                 <td valign="top" class="name">
+                                    <label for="supplier">Supplier:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'supplier','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
+                                                        name="supplier.id"
+                                                        value="${inventoryItemPurchaseInstance?.supplier?.id}">
+                                    </g:select>
+                                    <g:helpBalloon code="inventoryItemPurchase.supplier" />
+                                    <p><g:link controller="supplierDetailed" action="create">+Add Supplier</g:link></p>
+                                </td>
+                            </tr>
+                    
+                            <tr class="prop">
+                                <td valign="top" class="name">Quantity:</td>
+                                
+                                <td valign="top" class="value">
+                                    ${fieldValue(bean:inventoryItemPurchaseInstance, field:'quantity')}
+                                    <g:helpBalloon code="inventoryItemPurchase.quantity" />
+                                </td>
+                                
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="orderValueAmount">Order Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'orderValueAmount','errors')}">
+                                    <input type="text" id="orderValueAmount" name="orderValueAmount" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'orderValueAmount')}" />
+                                    <g:currencySelect name="orderValueCurrency"
+                                                                        value="${inventoryItemPurchaseInstance?.orderValueCurrency}"
+                                                                        from="${grailsApplication.config.currencyList}">
+                                    </g:currencySelect>
+                                    <g:helpBalloon code="inventoryItemPurchase.order.value" />
+                                </td>
+                            </tr>
+
+                            <g:if test="${inventoryItemPurchaseInstance.inventoryItemPurchaseType?.id == 4}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="invoiceNumber">Invoice Number:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'invoiceNumber','errors')}">
+                                        <input type="text" maxlength="50" id="invoiceNumber" name="invoiceNumber" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'invoiceNumber')}"/>
+                                    <g:helpBalloon code="inventoryItemPurchase.invoice.number" />
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <g:if test="${inventoryItemPurchaseInstance?.inventoryItemPurchaseType?.id > 0}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="receivedComplete">Received Complete:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:checkBox name="receivedComplete" value="${inventoryItemPurchaseInstance?.receivedComplete}" ></g:checkBox>
+                                    </td>
+                                </tr>
+                                
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="invoicePaymentApproved">Invoice Payment Approved:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:checkBox name="invoicePaymentApproved" value="${inventoryItemPurchaseInstance?.invoicePaymentApproved}" ></g:checkBox>
+                                    </td>
+                                </tr>
+                            </g:if>
+                            <g:else>
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="receivedComplete">Received Complete:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        ${fieldValue(bean:inventoryItemPurchaseInstance, field:'receivedComplete')}
+                                    </td>
+                                </tr>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="invoicePaymentApproved">Invoice Payment Approved:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        ${fieldValue(bean:inventoryItemPurchaseInstance, field:'invoicePaymentApproved')}
+                                    </td>
+                                </tr>
+                            </g:else>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:inventoryItemPurchaseInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="name">Entered By:</td>
+                            <td valign="top" class="value">
+                                <g:link controller="person" action="show" id="${inventoryItemPurchaseInstance?.enteredBy?.id}">
+                                    ${inventoryItemPurchaseInstance?.enteredBy?.encodeAsHTML()}
+                                </g:link>
+                                    on <g:formatDate date="${inventoryItemPurchaseInstance?.dateCreated}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                            </td>
+                        </tr>
+
+                        <g:if test="${inventoryItemPurchaseInstance.lastUpdatedBy}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Last Updated By:</td>
+                                <td valign="top" class="value">
+                                    <g:link controller="person" action="show" id="${inventoryItemPurchaseInstance?.lastUpdatedBy?.id}">
+                                        ${inventoryItemPurchaseInstance?.lastUpdatedBy.encodeAsHTML()}
+                                    </g:link>
+                                    on <g:formatDate date="${inventoryItemPurchaseInstance?.lastUpdated}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                                </td>
+                            </tr>
+                        </g:if >
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/receive.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/receive.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/receive.gsp	(revision 875)
@@ -0,0 +1,119 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Receive InventoryItemPurchase</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Receive Inventory</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${inventoryItemPurchaseInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryItemPurchaseInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="receiveSave" method="post" >
+                <g:hiddenField name="inventoryItem.id" value="${inventoryItemPurchaseInstance.inventoryItem?.id}" />
+                <g:hiddenField name="orderId" value="${orderId}" />
+                <g:hiddenField name="supplier.id" value="${inventoryItemPurchaseInstance.supplier?.id}" />
+                <g:hiddenField name="taskBudgetStatus.id" value="${inventoryItemPurchaseInstance.taskBudgetStatus?.id}" />
+                <g:hiddenField name="returnTo" value="${params.returnTo}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItem">Inventory Item:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:link controller="inventoryItemDetailed"
+                                                    action="show"
+                                                    id="${inventoryItemPurchaseInstance.inventoryItem.id}">
+                                        ${inventoryItemPurchaseInstance.inventoryItem.encodeAsHTML()}
+                                    </g:link>
+                                    <br />
+                                    Description: ${inventoryItemPurchaseInstance.inventoryItem.description.encodeAsHTML()}
+                                    <br />
+                                    Location: ${inventoryItemPurchaseInstance.inventoryItem.inventoryLocation.encodeAsHTML()}
+                                    <br />
+                                    Suppliers Part Number: ${inventoryItemPurchaseInstance.inventoryItem.suppliersPartNumber.encodeAsHTML()}
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="purchaseOrderNumber">Purchase Order #:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    ${inventoryItemPurchaseInstance.purchaseOrderNumber.encodeAsHTML()}
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="costCode">Cost Code:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'costCode','errors')}">
+                                    ${inventoryItemPurchaseInstance.costCode.encodeAsHTML()}
+                                </td>
+                            </tr> 
+                        
+                             <tr class="prop">
+                                 <td valign="top" class="name">
+                                    <label for="supplier">Supplier:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'supplier','errors')}">
+                                    ${inventoryItemPurchaseInstance.supplier}
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="quantity">Quantity:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'quantity','errors')}">
+                                    <input type="text" id="quantity" name="quantity" value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'quantity')}" />
+                                    ${inventoryItemPurchaseInstance.inventoryItem.unitOfMeasure.encodeAsHTML()}
+                                    <g:helpBalloon code="inventoryItemPurchase.receive.quantity" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="orderValueAmount">Receive Value:</label>
+                                </td>
+                                <td valign="top">
+                                    <input  class="medium ${hasErrors(bean:inventoryItemPurchaseInstance,field:'orderValueAmount','errors')}"
+                                                    type="text" id="orderValueAmount" name="orderValueAmount"
+                                                    value="${fieldValue(bean:inventoryItemPurchaseInstance,field:'orderValueAmount')}" />
+                                    ${inventoryItemPurchaseInstance.orderValueCurrency?.encodeAsHTML()}
+                                    <g:helpBalloon code="inventoryItemPurchase.receive.value" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryItemPurchaseInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:inventoryItemPurchaseInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/search.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/search.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/search.gsp	(revision 875)
@@ -0,0 +1,252 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Inventory Item Purchase Search</title>
+        <filterpane:includes />
+        <nav:resources override="true"/>
+        <export:resource />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <filterpane:currentCriteria domainBean="InventoryItemPurchase"
+                                    action="search"
+                                    dateFormat="EEE, dd-MMM-yyyy"
+                                    removeImgDir="images"
+                                    removeImgFile="bullet_delete.png"
+                                    title="Advanced Search"/>
+
+            <div class="paginateButtons">
+                <span class="searchButtons">
+                    <a href='' onclick="showElement('searchPane'); return false;">Quick</a>
+                </span>
+                Results: ${inventoryItemPurchaseList.size()} / ${inventoryItemPurchaseTotal}
+                <span class="searchButtons">
+                    <filterpane:filterButton text="Advanced" appliedText="Advanced" />
+                </span>
+            </div>
+
+            <jsUtil:toggleControl toggleId="options"
+                                                    imageId="optionsImg"
+                                                    closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                    openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                    text="${g.message(code: 'default.options.text')}"
+                                                    />
+
+            <div id="options" style="display:none;">
+                <g:form method="post" action="setSearchParamsMax" >
+                    <g:hiddenField name="params" value="${filterParams}" />
+                    <div class="dialog">
+                        <table>
+                            <tbody>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Results per page:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <input type="text" maxlength="4" id="description" name="newMax" value="${params.max}"/>
+
+                                        <span class="buttons">
+                                            <g:actionSubmit action="setSearchParamsMax" class="go" value="Update" />
+                                        </span>
+                                    </td>
+                                </tr>
+
+                            </tbody>
+                        </table>
+                    </div>
+                <export:formats  params="${filterParams}" formats="['csv', 'excel', 'pdf', 'rtf']"/>
+                </g:form>
+            </div>
+
+            <br />
+
+            <g:if test="${inventoryItemPurchaseList.size() > 10}">
+                <g:if test="${inventoryItemPurchaseTotal > inventoryItemPurchaseList.size()}">
+                    <div class="paginateButtons">
+                        <g:paginate action="search" total="${inventoryItemPurchaseTotal}" params="${filterParams}" />
+                    </div>
+                </g:if>
+            </g:if>
+
+            <g:if test="${inventoryItemPurchaseList.size() > 0}">
+                <div class="list">
+                    <table>
+                        <thead>
+                            <tr>
+                                <g:sortableColumn property="purchaseOrderNumber"
+                                                                    title="Order #"
+                                                                    params="${filterParams}"  />
+                                <g:sortableColumn property="date"
+                                                                    title="Date"
+                                                                    params="${filterParams}" />
+                                <g:sortableColumn property="inventoryItem"
+                                                                    title="Inventory Item"
+                                                                    params="${filterParams}" />
+                                <g:sortableColumn property="costCode"
+                                                                    title="Cost Code"
+                                                                    params="${filterParams}" />
+                                <g:sortableColumn property="quantity"
+                                                                    title="Quantity"
+                                                                    params="${filterParams}" />
+                                <g:sortableColumn property="orderValueAmount"
+                                                                    title="Order \$"
+                                                                    params="${filterParams}" />
+                                <g:sortableColumn property="inventoryItemPurchaseType"
+                                                                    title="Type"
+                                                                    params="${filterParams}" />
+                                <th>
+                                    <img  src="${resource(dir:'images/skin',file:'database_go_grey.png')}" alt="Show" title="Show" />
+                                </th>
+                                <th>
+                                    <img  src="${resource(dir:'images/skin',file:'basket_put_grey.png')}" alt="Receive" title="Receive" />
+                                </th>
+                                <th>
+                                    <img  src="${resource(dir:'images/skin',file:'tick_grey.png')}" alt="Approve" title="Approve Payment" />
+                                </th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <g:each in="${inventoryItemPurchaseList}" status="i" var="purchase">
+                                <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                                    <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}?returnTo=search"'>
+                                        ${fieldValue(bean:purchase, field:'purchaseOrderNumber')}
+                                    </td>
+                                    <td style="width:75px;" onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}?returnTo=search"'>
+                                        <g:formatDate date="${purchase.date}" format="EEE, dd-MMM-yyyy"/>
+                                    </td>
+                                    <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}?returnTo=search"'>
+                                        <b>${fieldValue(bean:purchase, field:'inventoryItem')}</b><br/>
+                                        ${purchase.inventoryItem.description?.encodeAsHTML()}
+                                    </td>
+                                    <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}?returnTo=search"'>
+                                        <b>${fieldValue(bean:purchase, field:'costCode')}</b><br/>
+                                        <g:if test="${purchase.invoiceNumber}">
+                                            Invoice # ${fieldValue(bean:purchase, field:'invoiceNumber')}<br/>
+                                        </g:if>
+                                        ${fieldValue(bean:purchase, field:'comment')}
+                                    </td>
+                                    <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}?returnTo=search"'>
+                                        ${fieldValue(bean:purchase, field:'quantity')}
+                                    </td>
+                                    <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}?returnTo=search"'>
+                                        ${fieldValue(bean:purchase, field:'orderValueAmount')}
+                                        ${fieldValue(bean:purchase, field:'orderValueCurrency')}
+                                    </td>
+                                    <td onclick='window.location = "${request.getContextPath()}/inventoryItemPurchaseDetailed/show/${purchase.id}?returnTo=search"'>
+                                        ${fieldValue(bean:purchase, field:'inventoryItemPurchaseType')}
+                                    </td>
+                                    <td class="notClickable">
+                                        <g:link controller="inventoryItemPurchaseDetailed" action="show" params="[id: purchase.id, returnTo: 'search']">
+                                            <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" title="Show" />
+                                        </g:link>
+                                    </td>
+
+                                    <g:if test="${purchase.inventoryItemPurchaseType.id == 1}">
+                                        <g:if test="${!purchase.receivedComplete}">
+                                            <td class="notClickable">
+                                                <g:link controller="inventoryItemPurchaseDetailed" action="receive" params="[id: purchase.id, returnTo: 'search']">
+                                                    <img  src="${resource(dir:'images/skin',file:'basket_put.png')}" alt="Receive" title="Receive" />
+                                                </g:link>
+                                            </td>
+                                            <td class="notClickable">
+                                            </td>
+                                        </g:if>
+                                        <g:else>
+                                            <td class="notClickable">
+                                            </td>
+                                            <td class="notClickable">
+                                            </td>
+                                        </g:else>
+                                    </g:if>
+                                    <g:elseif test="${(purchase.inventoryItemPurchaseType.id == 2)||(purchase.inventoryItemPurchaseType.id == 3)}">
+                                        <g:if test="${!purchase.invoicePaymentApproved}">
+                                            <td class="notClickable">
+                                            </td>
+                                            <td class="notClickable">
+                                                <g:link controller="inventoryItemPurchaseDetailed" action="approveInvoicePayment" params="[id: purchase.id, returnTo: 'search']">
+                                                    <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Approve" title="Approve Payment" />
+                                                </g:link>
+                                            </td>
+                                        </g:if>
+                                        <g:else>
+                                            <td class="notClickable">
+                                            </td>
+                                            <td class="notClickable">
+                                            </td>
+                                        </g:else>
+                                    </g:elseif>
+                                    <g:else>
+                                        <td class="notClickable">
+                                        </td>
+                                        <td class="notClickable">
+                                        </td>
+                                    </g:else>
+
+                                </tr>
+                            </g:each>
+                        </tbody>
+                    </table>
+                </div>
+            </g:if>
+            <div class="paginateButtons">
+                <g:paginate action="search" total="${inventoryItemPurchaseTotal}" params="${filterParams}" />
+            </div>
+
+            <filterpane:filterPane domainBean="InventoryItemPurchase"
+                                    title="Advanced Search"
+                                    action="search"
+                                    class="overlayPane"
+                                    excludeProperties="orderValueCurrency, dateCreated"
+                                    associatedProperties="inventoryItemPurchaseType.name, supplier.name"
+                                    filterPropertyValues="${['inventoryItemPurchaseType.name':[values:InventoryItemPurchaseType.findAllByIsActive(true)],
+                                                                                'supplier.name':[values:Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }],
+                                                                                date:[years: associatedPropertyValues.yearRange,precision:'day']
+                                                                                ]}"/>
+        </div> <!-- end body  -->
+
+        <!-- Start Search Pane -->
+        <div class="overlayPane" id="searchPane" style="display:none;">
+            <h2>Quick Search</h2>
+            <g:form method="post" id="searchForm" name="searchForm" >
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label>Type:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                <g:link controller="inventoryItemPurchaseDetailed"
+                                                action="search"
+                                                params="[quickSearch: 'searchAllOrders']">
+                                                All Orders
+                                </g:link>
+                                <br />
+                                <g:link controller="inventoryItemPurchaseDetailed" 
+                                                action="search"
+                                                params="[quickSearch: 'searchAllReceived']">
+                                                All Received
+                                </g:link>
+                            </td>
+                        </tr>
+
+                    </tbody>
+                </table>
+                <div class="buttons">
+                    <span class="button">
+                        <input type="button" value="${g.message(code:'fp.tag.filterPane.button.cancel.text', default:'Cancel')}" onclick="return hideElement('searchPane');" />
+                    </span>
+                </div>
+            </g:form>
+        </div> <!-- end search pane -->
+
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryItemPurchaseDetailed/show.gsp	(revision 875)
@@ -0,0 +1,151 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryItemPurchase</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Item:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="inventoryItemDetailed" action="show" id="${inventoryItemPurchaseInstance?.inventoryItem?.id}">${inventoryItemPurchaseInstance?.inventoryItem?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Purchase Type:</td>
+                            
+                            <td valign="top" class="value">${inventoryItemPurchaseInstance?.inventoryItemPurchaseType?.encodeAsHTML()}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Purchase Order #:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryItemPurchaseInstance, field:'purchaseOrderNumber')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Date:</td>
+                            <td valign="top" class="value">
+                                <g:formatDate date="${inventoryItemPurchaseInstance?.date}" format="EEE, dd-MMM-yyyy"/>
+                            </td>
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Cost Code:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="costCodeDetailed" action="show" id="${inventoryItemPurchaseInstance?.costCode?.id}">${inventoryItemPurchaseInstance?.costCode?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Budget Status:</td>
+                            
+                            <td valign="top" class="value">${inventoryItemPurchaseInstance?.taskBudgetStatus?.encodeAsHTML()}</td>
+                            
+                        </tr>
+                        
+                         <tr class="prop">
+                            <td valign="top" class="name">Supplier:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="supplierDetailed" action="show" id="${inventoryItemPurchaseInstance?.supplier?.id}">${inventoryItemPurchaseInstance?.supplier?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Quantity:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryItemPurchaseInstance, field:'quantity')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Order Value:</td>
+                            
+                            <td valign="top" class="value">
+                                ${fieldValue(bean:inventoryItemPurchaseInstance, field:'orderValueAmount')}
+                                ${inventoryItemPurchaseInstance.orderValueCurrency?.encodeAsHTML()}
+                            </td>
+                            
+                        </tr>
+
+                        <g:if test="${inventoryItemPurchaseInstance.inventoryItemPurchaseType?.id == 4}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Invoice Number:</td>
+                                <td valign="top" class="value">${fieldValue(bean:inventoryItemPurchaseInstance, field:'invoiceNumber')}</td>
+                            </tr>
+                        </g:if>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label for="receivedComplete">Received Complete:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                ${inventoryItemPurchaseInstance?.receivedComplete}
+                            </td>
+                        </tr>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="name">
+                                <label for="invoicePaymentApproved">Invoice Payment Approved:</label>
+                            </td>
+                            <td valign="top" class="value">
+                                ${inventoryItemPurchaseInstance?.invoicePaymentApproved}
+                            </td>
+                        </tr>
+                        
+                        <tr class="prop">
+                            <td valign="top" class="name">Comment:</td>
+                            <td valign="top" class="value">${fieldValue(bean:inventoryItemPurchaseInstance, field:'comment')}</td>
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Entered By:</td>
+                            <td valign="top" class="value">
+                                <g:link controller="person" action="show" id="${inventoryItemPurchaseInstance?.enteredBy?.id}">
+                                    ${inventoryItemPurchaseInstance?.enteredBy?.encodeAsHTML()}
+                                </g:link>
+                                    on <g:formatDate date="${inventoryItemPurchaseInstance?.dateCreated}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                            </td>
+                        </tr>
+
+                        <g:if test="${inventoryItemPurchaseInstance.lastUpdatedBy}">
+                            <tr class="prop">
+                                <td valign="top" class="name">Last Updated By:</td>
+                                <td valign="top" class="value">
+                                    <g:link controller="person" action="show" id="${inventoryItemPurchaseInstance?.lastUpdatedBy?.id}">
+                                        ${inventoryItemPurchaseInstance?.lastUpdatedBy.encodeAsHTML()}
+                                    </g:link>
+                                    on <g:formatDate date="${inventoryItemPurchaseInstance?.lastUpdated}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                                </td>
+                            </tr>
+                        </g:if >
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <g:hiddenField name="id" value="${inventoryItemPurchaseInstance?.id}" />
+                    <g:hiddenField name="returnTo" value="${params.returnTo}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryLocation</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryLocationInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryLocationInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryLocationInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:inventoryLocationInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryStore">Inventory Store:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryLocationInstance,field:'inventoryStore','errors')}">
+                                    <g:select optionKey="id" from="${InventoryStore.list()}" name="inventoryStore.id" value="${inventoryLocationInstance?.inventoryStore?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryLocationInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryLocationInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit InventoryLocation</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryLocationInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryLocationInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${inventoryLocationInstance?.id}" />
+                <input type="hidden" name="version" value="${inventoryLocationInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryLocationInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:inventoryLocationInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryStore">Inventory Store:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryLocationInstance,field:'inventoryStore','errors')}">
+                                    <g:select optionKey="id" from="${InventoryStore.list()}" name="inventoryStore.id" value="${inventoryLocationInstance?.inventoryStore?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryLocationInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryLocationInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItems">Inventory Items:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryLocationInstance,field:'inventoryItems','errors')}">
+                                    
+<ul>
+<g:each var="i" in="${inventoryLocationInstance?.inventoryItems?}">
+    <li><g:link controller="inventoryItemDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="inventoryItemDetailed" params="['inventoryLocation.id':inventoryLocationInstance?.id]" action="create">+Add Inventory Item</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/list.gsp	(revision 875)
@@ -0,0 +1,72 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>InventoryLocation List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                            <g:sortableColumn property="id" title="Id" />
+
+                            <g:sortableColumn property="name" title="Name" />
+
+                            <th>Inventory Store</th>
+
+                            <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${inventoryLocationInstanceList}" status="i" var="inventoryLocationInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryLocationDetailed/show/${inventoryLocationInstance.id}"'>
+                                ${fieldValue(bean:inventoryLocationInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryLocationDetailed/show/${inventoryLocationInstance.id}"'>
+                                ${fieldValue(bean:inventoryLocationInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryLocationDetailed/show/${inventoryLocationInstance.id}"'>
+                                ${fieldValue(bean:inventoryLocationInstance, field:'inventoryStore')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryLocationDetailed/show/${inventoryLocationInstance.id}"'>
+                                ${fieldValue(bean:inventoryLocationInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${inventoryLocationInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${inventoryLocationInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryLocationDetailed/show.gsp	(revision 875)
@@ -0,0 +1,76 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryLocation</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryLocationInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryLocationInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Store:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="inventoryStoreDetailed" action="show" id="${inventoryLocationInstance?.inventoryStore?.id}">${inventoryLocationInstance?.inventoryStore?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryLocationInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Items:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${inventoryLocationInstance.inventoryItems}">
+                                    <li><g:link controller="inventoryItemDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${inventoryLocationInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/create.gsp	(revision 875)
@@ -0,0 +1,86 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryMovement</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Inventory Movement</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryMovementInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryMovementInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+
+            <g:form action="save" method="post" >
+                <g:hiddenField name="inventoryItem.id" value="${inventoryMovementInstance?.inventoryItem?.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItem">Inventory Item:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementInstance,field:'inventoryItem','errors')}">
+                                    <g:link controller="inventoryItemDetailed" action="show" id="${inventoryMovementInstance?.inventoryItem?.id}" >
+                                        <g:fieldValue bean="${inventoryMovementInstance}" field="inventoryItem" />
+                                    </g:link>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="quantity">Quantity:</label>
+                                </td>
+                                <td valign="top">
+                                    <input class="medium ${hasErrors(bean:inventoryMovementInstance,field:'quantity','errors')}"
+                                                type="text" id="quantity" name="quantity"
+                                                value="${fieldValue(bean:inventoryMovementInstance,field:'quantity')}"/>
+                                                ${inventoryMovementInstance?.inventoryItem?.unitOfMeasure.encodeAsHTML()}
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryMovementType">Movement Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementInstance,field:'inventoryMovementType','errors')}">
+                                    <g:select optionKey="id" from="${inventoryMovementTypeList}" name="inventoryMovementType.id" value="${inventoryMovementInstance?.inventoryMovementType?.id}" ></g:select>
+                                </td>
+                            </tr>
+
+                            <g:if test="${inventoryMovementInstance?.task}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="taskInstance">Linking with task:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <g:hiddenField name="task.id" value="${inventoryMovementInstance.task.id}" />
+                                        <g:link controller="taskDetailed" action="show" id="${inventoryMovementInstance.task.id}" >
+                                            ${inventoryMovementInstance.task.encodeAsHTML()}
+                                        </g:link>
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                        </tbody>
+                    </table>
+                </div>
+
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/listInventoryMovements.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/listInventoryMovements.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/listInventoryMovements.gsp	(revision 875)
@@ -0,0 +1,76 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Inventory Movement List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>List Inventory Movements</h1>
+        </div>
+        <div class="body">
+             <g:link controller="inventoryItemDetailed" action="show" id="${inventoryItemInstance.id}">
+                <h1>Inventory Item: ${inventoryItemInstance.name.encodeAsHTML()}.</h1>
+            </g:link>
+            <g:if test="${flash.message}">
+                <div class="message">${flash.message}</div>
+            </g:if>
+
+            <div class="paginateButtons">
+                Results:${inventoryMovementListTotal}
+            </div>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn action="listInventoryMovements" property="quantity" title="Quantity" params="[id: inventoryItemInstance.id]"/>
+                        
+                   	        <g:sortableColumn action="listInventoryMovements"  property="inventoryMovementType" title="Movement Type" params="[id: inventoryItemInstance.id]" />
+                        
+                            <g:sortableColumn action="listInventoryMovements"  property="date" title="Date" params="[id: inventoryItemInstance.id]" />
+                        
+                   	        <g:sortableColumn action="listInventoryMovements"  property="person" title="Person" params="[id: inventoryItemInstance.id]" />
+
+                            <th></th>
+                   	    
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${inventoryMovementList}" status="i" var="inventoryMovementInstance">
+                    <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                ${fieldValue(bean:inventoryMovementInstance, field:'quantity')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                ${fieldValue(bean:inventoryMovementInstance, field:'inventoryMovementType')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                <g:formatDate date="${inventoryMovementInstance.date}" format="EEE, dd-MMM-yyyy"/>
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                ${fieldValue(bean:inventoryMovementInstance, field:'person')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${inventoryMovementInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate action="listInventoryMovements" id="${inventoryItemInstance.id}" total="${inventoryMovementListTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryMovementDetailed/show.gsp	(revision 875)
@@ -0,0 +1,92 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryMovement</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Inventory Movement</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryMovementInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryMovementInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryMovementInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Item:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="inventoryItemDetailed" action="show" id="${inventoryMovementInstance?.inventoryItem?.id}">${inventoryMovementInstance?.inventoryItem?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Quantity:</td>
+                            
+                            <td valign="top" class="value">
+                                ${fieldValue(bean:inventoryMovementInstance, field:'quantity')}
+                                ${inventoryMovementInstance.inventoryItem.unitOfMeasure.encodeAsHTML()}
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Movement Type:</td>
+                            
+                            <td valign="top" class="value">${inventoryMovementInstance?.inventoryMovementType?.encodeAsHTML()}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Task:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="taskDetailed" action="show" id="${inventoryMovementInstance?.task?.id}">${inventoryMovementInstance?.task?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Date:</td>
+                            
+                            <td valign="top" class="value">
+                                <g:formatDate date="${inventoryMovementInstance?.date}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                            </td>
+                            
+                        </tr>
+
+                         <tr class="prop">
+                            <td valign="top" class="name">Person:</td>
+
+                            <td valign="top" class="value">${inventoryMovementInstance?.person?.encodeAsHTML()}</td>
+
+                        </tr>
+
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${inventoryMovementInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/create.gsp	(revision 875)
@@ -0,0 +1,73 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryMovementType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">InventoryMovementType List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create InventoryMovementType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryMovementTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryMovementTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:inventoryMovementTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="incrementsInventory">Increments Inventory:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'incrementsInventory','errors')}">
+                                    <g:checkBox name="incrementsInventory" value="${inventoryMovementTypeInstance?.incrementsInventory}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryMovementTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:inventoryMovementTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/edit.gsp	(revision 875)
@@ -0,0 +1,93 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit InventoryMovementType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">InventoryMovementType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New InventoryMovementType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit InventoryMovementType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryMovementTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryMovementTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${inventoryMovementTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${inventoryMovementTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:inventoryMovementTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="incrementsInventory">Increments Inventory:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'incrementsInventory','errors')}">
+                                    <g:checkBox name="incrementsInventory" value="${inventoryMovementTypeInstance?.incrementsInventory}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryMovements">Inventory Movements:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'inventoryMovements','errors')}">
+                                    
+<ul>
+<g:each var="i" in="${inventoryMovementTypeInstance?.inventoryMovements?}">
+    <li><g:link controller="inventoryMovement" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="inventoryMovement" params="['inventoryMovementType.id':inventoryMovementTypeInstance?.id]" action="create">Add InventoryMovement</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryMovementTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryMovementTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:inventoryMovementTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/list.gsp	(revision 875)
@@ -0,0 +1,59 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>InventoryMovementType List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New InventoryMovementType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>InventoryMovementType List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="incrementsInventory" title="Increments Inventory" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${inventoryMovementTypeInstanceList}" status="i" var="inventoryMovementTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${inventoryMovementTypeInstance.id}">${fieldValue(bean:inventoryMovementTypeInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:inventoryMovementTypeInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:inventoryMovementTypeInstance, field:'incrementsInventory')}</td>
+                        
+                            <td>${fieldValue(bean:inventoryMovementTypeInstance, field:'isActive')}</td>
+                        
+                            <td>${fieldValue(bean:inventoryMovementTypeInstance, field:'name')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${inventoryMovementTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryMovementType/show.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryMovementType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">InventoryMovementType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New InventoryMovementType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show InventoryMovementType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryMovementTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryMovementTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Increments Inventory:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryMovementTypeInstance, field:'incrementsInventory')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Movements:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${inventoryMovementTypeInstance.inventoryMovements}">
+                                    <li><g:link controller="inventoryMovement" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryMovementTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryMovementTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${inventoryMovementTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/create.gsp	(revision 875)
@@ -0,0 +1,73 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryStore</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryStoreInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryStoreInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:inventoryStoreInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:inventoryStoreInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryStoreInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="site">Site:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'site','errors')}">
+                                    <g:select optionKey="id" from="${Site.list()}" name="site.id" value="${inventoryStoreInstance?.site?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,93 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit InventoryStore</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryStoreInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryStoreInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${inventoryStoreInstance?.id}" />
+                <input type="hidden" name="version" value="${inventoryStoreInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:inventoryStoreInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:inventoryStoreInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryStoreInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="site">Site:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'site','errors')}">
+                                    <g:select optionKey="id" from="${Site.list()}" name="site.id" value="${inventoryStoreInstance?.site?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryLocations">Inventory Locations:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryStoreInstance,field:'inventoryLocations','errors')}">
+                                    
+<ul>
+<g:each var="i" in="${inventoryStoreInstance?.inventoryLocations?}">
+    <li><g:link controller="inventoryLocationDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="inventoryLocationDetailed" params="['inventoryStore.id':inventoryStoreInstance?.id]" action="create">+Add Inventory Location</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/list.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>InventoryStore List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                            <g:sortableColumn property="id" title="Id" />
+
+                            <g:sortableColumn property="name" title="Name" />
+
+                            <g:sortableColumn property="description" title="Description" />
+
+                            <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th>Site</th>
+
+                            <th></th>
+                   	    
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${inventoryStoreInstanceList}" status="i" var="inventoryStoreInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryStoreDetailed/show/${inventoryStoreInstance.id}"'>
+                                ${fieldValue(bean:inventoryStoreInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryStoreDetailed/show/${inventoryStoreInstance.id}"'>
+                                ${fieldValue(bean:inventoryStoreInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryStoreDetailed/show/${inventoryStoreInstance.id}"'>
+                                ${fieldValue(bean:inventoryStoreInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryStoreDetailed/show/${inventoryStoreInstance.id}"'>
+                                ${fieldValue(bean:inventoryStoreInstance, field:'isActive')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryStoreDetailed/show/${inventoryStoreInstance.id}"'>
+                                ${fieldValue(bean:inventoryStoreInstance, field:'site')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${inventoryStoreInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${inventoryStoreInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryStoreDetailed/show.gsp	(revision 875)
@@ -0,0 +1,83 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryStore</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryStoreInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryStoreInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryStoreInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryStoreInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Site:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="siteDetailed" action="show" id="${inventoryStoreInstance?.site?.id}">${inventoryStoreInstance?.site?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Locations:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${inventoryStoreInstance.inventoryLocations}">
+                                    <li><g:link controller="inventoryLocationDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${inventoryStoreInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryType/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryType/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryType/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create InventoryType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">InventoryType List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create InventoryType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:inventoryTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:inventoryTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryType/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryType/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryType/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit InventoryType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">InventoryType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New InventoryType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit InventoryType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${inventoryTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${inventoryTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${inventoryTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${inventoryTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:inventoryTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItems">Inventory Items:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryTypeInstance,field:'inventoryItems','errors')}">
+                                    
+<ul>
+<g:each var="i" in="${inventoryTypeInstance?.inventoryItems?}">
+    <li><g:link controller="inventoryItem" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="inventoryItem" params="['inventoryType.id':inventoryTypeInstance?.id]" action="create">Add InventoryItem</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${inventoryTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:inventoryTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:inventoryTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryType/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryType/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryType/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>InventoryType List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New InventoryType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>InventoryType List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${inventoryTypeInstanceList}" status="i" var="inventoryTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${inventoryTypeInstance.id}">${fieldValue(bean:inventoryTypeInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:inventoryTypeInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:inventoryTypeInstance, field:'isActive')}</td>
+                        
+                            <td>${fieldValue(bean:inventoryTypeInstance, field:'name')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${inventoryTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/inventoryType/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/inventoryType/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/inventoryType/show.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show InventoryType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">InventoryType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New InventoryType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show InventoryType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Items:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${inventoryTypeInstance.inventoryItems}">
+                                    <li><g:link controller="inventoryItem" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:inventoryTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${inventoryTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/layouts/main.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/layouts/main.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/layouts/main.gsp	(revision 875)
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+    <head>
+        <title><g:layoutTitle default="gnuMims" /></title>
+        <link rel="stylesheet" href="${resource(dir:'css',file:'main.css')}" />
+        <link rel="shortcut icon" href="${resource(dir:'images',file:'gnuMimsIcon.ico')}" type="image/x-icon" />
+        <g:javascript library="jquery" />
+        <g:javascript library="prototype/prototype" />
+        <g:javascript library="prototype/effects" />
+        <g:javascript library="application" />
+        <g:javascript src="overlayPane.js" />
+        <jsUtil:resources />
+        <gnuMims:resources />
+        <nav:resources override="true"/>
+        <g:helpBalloons icon="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}"
+                                        button="${resource(plugin:'help-balloons', dir:'images', file:'balloon-button.png')}"
+                                        balloonPrefix="${resource(plugin:'help-balloons', dir:'images')}/balloon-"/>
+        <g:layoutHead />
+    </head>
+
+    <!-- Added g:pageProperty so that onload in each page works -->
+    <body onload="${pageProperty(name: 'body.onload')}">
+        <div id="wrapper" style="height: 100%;">
+            <div id="top">
+            </div>
+            <div id="content" align="center">
+                <div id="spinner" class="spinner" style="display:none;">
+                    <img src="${resource(dir:'images',file:'loading_bar.gif')}" alt="Spinner" />
+                </div>
+                <div id="jQueryAjaxLoading" class="jQueryAjaxLoading" style="display:none;">
+                    <img src="${resource(dir:'images',file:'loading.gif')}" alt="Loading" title="Loading" />
+                </div>
+                <div id="jQueryAjaxDefaultError" class="message_error" style="display:none;">
+                    <g:message code="ajax.default.could.not.perform.operation" />
+                </div>
+                <g:if env="production">
+                    <div id="Header">
+                        <a href="javascript: openWindow('http://www.gnumims.org')" id=HeaderLink></a>
+                    </div>
+                </g:if>
+                <g:else>
+                    <div id="HeaderDev">
+                        <a href="javascript: openWindow('http://www.gnumims.org')" id=HeaderLink></a>
+                    </div>
+                </g:else>
+
+                <g:isLoggedIn>
+                    <div class="appControl">
+                        <g:link controller="logout" class="logoutButton">
+                                Log out (<g:loggedInUsername/>)
+                        </g:link>
+                        <div id="menu">
+                            <nav:render group="nav"/>
+                        </div>
+                        <div class='app_help'>
+                            <a href="javascript: openWindow('http://www.youtube.com/gnuMims')">
+                                <img src="${resource(dir:'images/skin',file:'help.png')}" alt="Help" title="Help"/>
+                            </a>
+                        </div>
+                        <gnuMims:assetTreeButton />
+                    </div>
+                </g:isLoggedIn>
+
+                <g:layoutBody />
+
+            </div> <!-- content -->
+            <div id="bottom">
+            </div>
+        </div> <!-- wrapper -->
+
+        <!-- Asset Tree Pane -->
+        <gnuMims:assetTreePane />
+
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/login/auth.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/login/auth.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/login/auth.gsp	(revision 875)
@@ -0,0 +1,121 @@
+<head>
+<meta name='layout' content='main' />
+<title>Login</title>
+<style type='text/css' media='screen'>
+#login {
+    margin:15px 0px; padding:0px;
+    text-align:center;
+}
+#login .inner {
+    width:260px;
+    margin:0px auto;
+    text-align:left;
+    padding:10px;
+/*	border-top:1px dashed #499ede;
+    border-bottom:1px dashed #499ede;*/
+/*	background-color:#EEF;*/
+}
+#login .inner .fheader {
+    padding:4px;margin:3px 0px 3px 0;color:#2e3741;font-size:14px;font-weight:bold;
+}
+#login .inner .cssform p {
+    clear: left;
+    margin: 0;
+    padding: 5px 0 0 0;
+    padding-left: 105px;
+/*	border-top: 1px dashed gray;*/
+    margin-bottom: 10px;
+    height: 1%;
+}
+#login .loginButton {
+    float: left;
+    background: #fff url(../images/skin/shadow.jpg) bottom repeat-x;
+    border: 1px solid #ccc;
+    border-color: #ccc #aaa #aaa #ccc;
+    margin: 0;
+}
+#login .inner .cssform input[type='text'] {
+    width: 120px;
+}
+#login .inner .cssform input[type='submit'] {
+    background: transparent url(../images/skin/key_go.png) 5px 50% no-repeat;
+    padding-left: 28px;
+    border: none;
+    cursor: pointer;
+    margin: 0;
+    overflow: hidden;
+}
+#login .inner .cssform input[type='submit']:link {
+}
+#login .inner .cssform input[type='submit']:visited {
+}
+#login .inner .cssform input[type='submit']:hover {
+    /*background: #bfdaff;*/
+}
+#login .inner .cssform input[type='submit']:focus {
+}
+#login .inner .cssform label {
+    font-weight: bold;
+    float: left;
+    margin-left: -105px;
+    width: 100px;
+    padding: 5px 0 0 0;
+}
+#login .inner .login_message {color:red;}
+#login .inner .text_ {width:120px;}
+#login .inner .chk {height:12px;}
+</style>
+</head>
+
+<body>
+    <div id='login'>
+        <h1>Welcome to gnuMims please log in</h1>
+
+        <g:if env="development">
+        The demo users are <b>user</b>, <b>manager</b> and  <b>admin</b> all having the password: <b>pass</b>
+        </g:if>
+
+        <div class='inner'>
+            <g:if test='${flash.message}'>
+            <div class='login_message'>${flash.message}</div>
+            </g:if>
+            <div class='fheader'></div>
+            <form action='${postUrl}' method='POST' id='loginForm' class='cssform'>
+                <p>
+                    <label for='j_username'>Login ID</label>
+
+                    <g:if env="production">
+                        <input type='text' class='text_' name='j_username' id='j_username'/>
+                    </g:if>
+                    <g:else >
+                        <input type='text' class='text_' name='j_username' id='j_username' value='manager'  />
+                    </g:else >
+
+                </p>
+                <p>
+                    <label for='j_password'>Password</label>
+
+                    <g:if env="production">
+                        <input type='password' class='text_' name='j_password' id='j_password' />
+                    </g:if>
+                    <g:else >
+                        <input type='password' class='text_' name='j_password' id='j_password' value="pass" />
+                    </g:else >
+                </p>
+
+                <p>
+                    <span class="loginButton">
+                        <input type='submit' value='Login' />
+                    </span>
+                </p>
+            </form>
+        </div>
+    </div>
+<script type='text/javascript'>
+<!--
+(function(){
+    document.forms['loginForm'].elements['j_username'].focus();
+})();
+// -->
+</script>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/login/denied.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/login/denied.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/login/denied.gsp	(revision 875)
@@ -0,0 +1,6 @@
+<meta name='layout' content='main' />
+<title>Denied</title>
+
+<div class='body'>
+	<div class='errors'>Sorry, you're not authorized to view this page.</div>
+</div>
Index: /branches/features/grailsUpgrade/grails-app/views/login/openIdAuth.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/login/openIdAuth.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/login/openIdAuth.gsp	(revision 875)
@@ -0,0 +1,67 @@
+<head>
+<meta name='layout' content='main' />
+<title>Login</title>
+<style type='text/css' media='screen'>
+#login {
+	margin:15px 0px; padding:0px;
+	text-align:center;
+}
+#login .inner {
+	width:260px;
+	margin:0px auto;
+	text-align:left;
+	padding:10px;
+	border-top:1px dashed #499ede;
+	border-bottom:1px dashed #499ede;
+	background-color:#EEF;
+}
+#login .inner .fheader {
+	padding:4px;margin:3px 0px 3px 0;color:#2e3741;font-size:14px;font-weight:bold;
+}
+#login .inner .cssform p{
+	clear: left;
+	margin: 0;
+	padding: 5px 0 8px 0;
+	padding-left: 105px;
+	border-top: 1px dashed gray;
+	margin-bottom: 10px;
+	height: 1%;
+}
+#login .inner .cssform input[type='text']{ 
+	width: 120px;
+}
+#login .inner .cssform label{
+	font-weight: bold;
+	float: left;
+	margin-left: -105px; 
+	width: 100px;
+}
+#login .inner .login_message {color:red;}
+#login .inner .text_ {width:120px;}
+</style>
+</head>
+
+<body>
+	<div id='login'>
+		<div class='inner'>
+			<g:if test='${flash.message}'>
+			<div class='login_message'>${flash.message}</div>
+			</g:if>
+			<div class='fheader'>Please Login..</div>
+			<form action='${postUrl}' method='POST' id='loginForm' class='cssform'>
+				<p>
+					<label for='j_username'>OpenID Identity</label>
+					<input type='text' class='text_' name='j_username' />
+				</p>
+				<p>
+					<input type='submit' value='Login' />
+				</p>
+			</form>
+		</div>
+	</div>
+<script type='text/javascript'>
+(function(){
+	document.forms['loginForm'].elements['j_username'].focus();
+})();
+</script>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create MaintenancePolicy</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${maintenancePolicyInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${maintenancePolicyInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:maintenancePolicyInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:maintenancePolicyInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:maintenancePolicyInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:maintenancePolicyInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:maintenancePolicyInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${maintenancePolicyInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,68 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit MaintenancePolicy</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${maintenancePolicyInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${maintenancePolicyInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${maintenancePolicyInstance?.id}" />
+                <input type="hidden" name="version" value="${maintenancePolicyInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:maintenancePolicyInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:maintenancePolicyInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:maintenancePolicyInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:maintenancePolicyInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:maintenancePolicyInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${maintenancePolicyInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/list.gsp	(revision 875)
@@ -0,0 +1,70 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>MaintenancePolicy List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                            <g:sortableColumn property="id" title="Id" />
+
+                            <g:sortableColumn property="name" title="Name" />
+
+                            <g:sortableColumn property="description" title="Description" />
+
+                            <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${maintenancePolicyInstanceList}" status="i" var="maintenancePolicyInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/maintenancePolicyDetailed/show/${maintenancePolicyInstance.id}"'>
+                                ${fieldValue(bean:maintenancePolicyInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/maintenancePolicyDetailed/show/${maintenancePolicyInstance.id}"'>
+                                ${fieldValue(bean:maintenancePolicyInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/maintenancePolicyDetailed/show/${maintenancePolicyInstance.id}"'>
+                                ${fieldValue(bean:maintenancePolicyInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/maintenancePolicyDetailed/show/${maintenancePolicyInstance.id}"'>
+                                ${fieldValue(bean:maintenancePolicyInstance, field:'isActive')}
+                            </td>
+                            
+                            <td class="notClickable">
+                                <g:link action="show" id="${maintenancePolicyInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${maintenancePolicyInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/maintenancePolicyDetailed/show.gsp	(revision 875)
@@ -0,0 +1,63 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show MaintenancePolicy</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:maintenancePolicyInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:maintenancePolicyInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:maintenancePolicyInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:maintenancePolicyInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${maintenancePolicyInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/period/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/period/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/period/create.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Period</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">Period List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create Period</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${periodInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${periodInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:periodInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${periodInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="period">Period:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:periodInstance,field:'period','errors')}">
+                                    <input type="text" id="period" name="period" value="${fieldValue(bean:periodInstance,field:'period')}"/>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/period/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/period/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/period/edit.gsp	(revision 875)
@@ -0,0 +1,75 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Period</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">Period List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New Period</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit Period</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${periodInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${periodInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${periodInstance?.id}" />
+                <input type="hidden" name="version" value="${periodInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:periodInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${periodInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="period">Period:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:periodInstance,field:'period','errors')}">
+                                    <input type="text" id="period" name="period" value="${fieldValue(bean:periodInstance,field:'period')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskRecurringSchedules">Task Recurring Schedules:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:periodInstance,field:'taskRecurringSchedules','errors')}">
+                                    
+<ul>
+<g:each var="t" in="${periodInstance?.taskRecurringSchedules?}">
+    <li><g:link controller="taskRecurringSchedule" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="taskRecurringSchedule" params="['period.id':periodInstance?.id]" action="create">Add TaskRecurringSchedule</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/period/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/period/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/period/list.gsp	(revision 875)
@@ -0,0 +1,51 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Period List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New Period</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Period List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                   	        <g:sortableColumn property="period" title="Period" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${periodInstanceList}" status="i" var="periodInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${periodInstance.id}">${fieldValue(bean:periodInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:periodInstance, field:'isActive')}</td>
+                        
+                            <td>${fieldValue(bean:periodInstance, field:'period')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${periodInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/period/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/period/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/period/show.gsp	(revision 875)
@@ -0,0 +1,70 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Period</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">Period List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New Period</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show Period</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:periodInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:periodInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Period:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:periodInstance, field:'period')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Task Recurring Schedules:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="t" in="${periodInstance.taskRecurringSchedules}">
+                                    <li><g:link controller="taskRecurringSchedule" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${periodInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/person/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/person/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/person/create.gsp	(revision 875)
@@ -0,0 +1,152 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Create Person</title>
+    <nav:resources override="true"/>
+</head>
+
+<body>
+
+    <div class="nav">
+        <nav:renderSubItems group="navAlt"/>
+    </div>
+
+    <div class="body">
+        <g:render template="/shared/messages" />
+        <g:hasErrors bean="${person}">
+        <div class="errors">
+            <g:renderErrors bean="${person}" as="list" />
+        </div>
+        </g:hasErrors>
+        <g:form action="save">
+            <div class="dialog">
+                <table>
+                <tbody>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="loginName">Login Name:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'loginName','errors')}">
+                            <input type="text" id="loginName" name="loginName" value="${person.loginName?.encodeAsHTML()}"/>
+                            <g:helpBalloon class="helpballoon" code="person.loginName" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="firstName">First Name:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'firstName','errors')}">
+                            <input type="text" id="firstName" name="firstName" value="${person.firstName?.encodeAsHTML()}"/>
+                            <g:helpBalloon class="helpballoon" code="person.firstName" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="lastName">Last Name:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'lastName','errors')}">
+                            <input type="text" id="lastName" name="lastName" value="${person.lastName?.encodeAsHTML()}"/>
+                            <g:helpBalloon class="helpballoon" code="person.lastName" />
+                        </td>
+                    </tr>
+
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="pass">Password:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'pass','errors')}">
+                            <input type="password" id="pass" name="pass"/>
+                            <g:helpBalloon class="helpballoon" code="person.password" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="isActive">Active:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'isActive','errors')}">
+                            <g:checkBox name="isActive" value="${person.isActive}" ></g:checkBox>
+                            <g:helpBalloon class="helpballoon" code="person.isActive" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="description">Description:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'description','errors')}">
+                            <input type="text" id="description" name="description" value="${person.description?.encodeAsHTML()}"/>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="employeeID">employee ID:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'employeeID','errors')}">
+                            <input type="text" id="employeeID" name="employeeID" value="${person.employeeID?.encodeAsHTML()}"/>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="department">Department:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'department','errors')}">
+                            <g:select optionKey="id" from="${Department.list()}" name="department.id" value="${person?.department?.id}" noSelection="['null':'--None--']"></g:select>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="personGroups">Groups:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'personGroups','errors')}">
+                            <g:helpBalloon class="helpballoon" code="person.personGroups" />
+                            <custom:checkBoxList name="personGroups"
+                                                            from="${PersonGroup.findAllByIsActive(true)}"
+                                                            value="${person?.personGroups?.collect{it.id}}"
+                                                            optionKey="id"
+                                                            sortBy="name"
+                                                            linkController="personGroupDetailed"
+                                                            linkAction="show"/>
+                            <g:link controller="personGroupDetailed" action="create">+Add Group</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="purchasingGroups">Purchasing Groups:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'purchasingGroups','errors')}">
+                            <g:helpBalloon class="helpballoon" code="person.purchasingGroups" />
+                            <custom:checkBoxList name="purchasingGroups"
+                                                            from="${PurchasingGroup.findAllByIsActive(true)}"
+                                                            value="${person?.purchasingGroups?.collect{it.id}}"
+                                                            optionKey="id"
+                                                            sortBy="name"
+                                                            linkController="purchasingGroupDetailed"
+                                                            linkAction="show"/>
+                            <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name" align="left">
+                            Authorities:
+                        </td>
+                        <td valign="top" class="name" align="left">
+                            <g:helpBalloon class="helpballoon" code="person.authorities" />
+                        </td>
+                    </tr>
+
+                    <g:each in="${authorityList}">
+                    <tr>
+                        <td valign="top" class="name" align="left">${it.description.encodeAsHTML()}</td>
+                        <td align="left">
+                            <g:checkBox name="${it.authority}" value="${it.authority == 'ROLE_AppUser'}"/>
+                        </td>
+                    </tr>
+                    </g:each>
+
+                </tbody>
+                </table>
+            </div>
+
+            <div class="buttons">
+                <span class="button"><input class="save" type="submit" value="Create" /></span>
+            </div>
+
+        </g:form>
+
+    </div>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/person/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/person/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/person/edit.gsp	(revision 875)
@@ -0,0 +1,191 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Edit Person</title>
+    <nav:resources override="true"/>
+</head>
+
+<body>
+
+    <div class="nav">
+        <nav:renderSubItems group="navAlt"/>
+    </div>
+
+    <div class="body">
+        <g:render template="/shared/messages" />
+        <g:hasErrors bean="${person}">
+        <div class="errors">
+            <g:renderErrors bean="${person}" as="list" />
+        </div>
+        </g:hasErrors>
+
+    <!--<div class="prop">
+            <span class="name">ID: ${person.id}</span>
+        </div>-->
+
+        <g:form>
+            <input type="hidden" name="id" value="${person.id}" />
+            <input type="hidden" name="version" value="${person.version}" />
+            <input type="hidden" name="password" value="${person.password}" />
+            <div class="dialog">
+                <table>
+                <tbody>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="loginName">Login Name:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'loginName','errors')}">
+                            <input type="text" id="loginName" name="loginName" value="${person.loginName?.encodeAsHTML()}"/>
+                            <g:helpBalloon class="helpballoon" code="person.loginName" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="firstName">First Name:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'firstName','errors')}">
+                            <input type="text" id="firstName" name="firstName" value="${person.firstName?.encodeAsHTML()}"/>
+                            <g:helpBalloon class="helpballoon" code="person.firstName" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="lastName">Last Name:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'lastName','errors')}">
+                            <input type="text" id="lastName" name="lastName" value="${person.lastName?.encodeAsHTML()}"/>
+                            <g:helpBalloon class="helpballoon" code="person.lastName" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="pass">Password:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'pass','errors')}">
+                            <input type="password" id="pass" name="pass"  value="${person.pass?.encodeAsHTML()}"/>
+                            <g:helpBalloon class="helpballoon" code="person.password" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="isActive">Active:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'isActive','errors')}">
+                            <g:checkBox name="isActive" value="${person.isActive}"/>
+                            <g:helpBalloon class="helpballoon" code="person.isActive" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="description">Description:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'description','errors')}">
+                            <input type="text" id="description" name="description" value="${person.description?.encodeAsHTML()}"/>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="addresses">Contact:</label>
+                        </td>
+                        <td valign="top" class="value">
+                            <ul>
+                            <g:each var="i" in="${person?.contacts}">
+                                <li><g:link controller="contactDetailed" action="show" id="${i.id}">
+                                    ${i?.encodeAsHTML()}
+                                </g:link></li>
+                            </g:each>
+                            </ul>
+                            <g:link controller="contactDetailed" params="['person.id':person?.id]" action="create">+Add Contact</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="addresses">Addresses:</label>
+                        </td>
+                        <td valign="top" class="value">
+                            <ul>
+                            <g:each var="i" in="${person?.addresses}">
+                                <li><g:link controller="addressDetailed" action="show" id="${i.id}">
+                                    ${i?.encodeAsHTML()}
+                                </g:link></li>
+                            </g:each>
+                            </ul>
+                            <g:link controller="addressDetailed" params="['person.id':person?.id]" action="create">+Add Address</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name"><label for="employeeID">employee ID:</label></td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'employeeID','errors')}">
+                            <input type="text" id="employeeID" name="employeeID" value="${person.employeeID?.encodeAsHTML()}"/>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="department">Department:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'department','errors')}">
+                            <g:select optionKey="id" from="${Department.list()}" name="department.id" value="${person?.department?.id}" noSelection="['null':'--None--']"></g:select>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="personGroups">Groups:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'personGroups','errors')}">
+                            <g:helpBalloon class="helpballoon" code="person.personGroups" />
+                            <custom:checkBoxList name="personGroups"
+                                                            from="${PersonGroup.findAllByIsActive(true)}"
+                                                            value="${person?.personGroups?.collect{it.id}}"
+                                                            optionKey="id"
+                                                            sortBy="name"
+                                                            linkController="personGroupDetailed"
+                                                            linkAction="show"/>
+                            <g:link controller="personGroupDetailed" action="create">+Add Group</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">
+                            <label for="purchasingGroups">Purchasing Groups:</label>
+                        </td>
+                        <td valign="top" class="value ${hasErrors(bean:person,field:'purchasingGroups','errors')}">
+                            <g:helpBalloon class="helpballoon" code="person.purchasingGroups" />
+                            <custom:checkBoxList name="purchasingGroups"
+                                                            from="${PurchasingGroup.findAllByIsActive(true)}"
+                                                            value="${person?.purchasingGroups?.collect{it.id}}"
+                                                            optionKey="id"
+                                                            sortBy="name"
+                                                            linkController="purchasingGroupDetailed"
+                                                            linkAction="show"/>
+                            <g:link controller="purchasingGroupDetailed" action="create">+Add Group</g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name" align="left">
+                            Authorities:
+                        </td>
+                        <td valign="top" class="name" align="left">
+                            <g:helpBalloon class="helpballoon" code="person.authorities" />
+                        </td>
+                    </tr>
+
+                    <g:each var="entry" in="${roleMap}">
+                    <tr>
+                        <td valign="top" class="name" align="left">${entry.key.description.encodeAsHTML()}</td>
+                        <td align="left"><g:checkBox name="${entry.key.authority}" value="${entry.value}"/></td>
+                    </tr>
+                    </g:each>
+
+                </tbody>
+                </table>
+            </div>
+
+            <div class="buttons">
+                <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+            </div>
+
+        </g:form>
+
+    </div>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/person/importPersons.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/person/importPersons.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/person/importPersons.gsp	(revision 875)
@@ -0,0 +1,35 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Import Persons</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Import Persons</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:uploadForm action="importPersonsSave" onsubmit="return Lightbox.loading();">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="file">File:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <input type="file" id="file" name="file" size="40"/>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:uploadForm>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/person/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/person/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/person/list.gsp	(revision 875)
@@ -0,0 +1,133 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Person List</title>
+    <filterpane:includes />
+    <nav:resources override="true"/>
+</head>
+
+<body>
+
+    <div class="nav">
+        <nav:renderSubItems group="navAlt"/>
+    </div>
+
+    <div class="body">
+        <g:if test="${flash.message}">
+        <div class="message">${flash.message}</div>
+        </g:if>
+        <filterpane:currentCriteria domainBean="Person"
+                                action="list"
+                                dateFormat="EEE, dd-MMM-yyyy"
+                                removeImgDir="images" 
+                                removeImgFile="bullet_delete.png"
+                                title="Search"/>
+
+        <div class="paginateButtons">
+            Results: ${personList.size()} / ${personTotal}
+            <span class="searchButtons">
+                <filterpane:filterButton text="Search" appliedText="Change Search" />
+            </span>
+        </div>
+
+        <jsUtil:toggleControl toggleId="options"
+                                                imageId="optionsImg"
+                                                closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                text="${g.message(code: 'default.options.text')}"
+                                                />
+
+        <div id="options" style="display:none;">
+            <g:form method="post" >
+                <g:hiddenField name="params" value="${filterParams}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="max">Persons:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:link action="exportPersonsTemplate">
+                                        Template
+                                    </g:link>
+                                    /
+                                    <g:link action="importPersons">
+                                        Import
+                                    </g:link>
+                                </td>
+                            </tr>
+
+                        </tbody>
+                    </table>
+                </div>
+            </g:form>
+        </div>
+
+        <br />
+
+        <g:if test="${personList.size() > 0}">
+            <div class="list">
+                <table>
+                <thead>
+                    <tr>
+                        <g:sortableColumn property="id" title="Id" params="${filterParams}" />
+                        <g:sortableColumn property="loginName" title="Login Name" params="${filterParams}" />
+                        <g:sortableColumn property="firstName" title="First Name" params="${filterParams}" />
+                        <g:sortableColumn property="lastName" title="Last Name" params="${filterParams}" />
+                        <g:sortableColumn property="isActive" title="Active" params="${filterParams}" />
+                        <th></th>
+                    </tr>
+                </thead>
+                <tbody>
+                <g:each in="${personList}" status="i" var="person">
+                    <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                        <td onclick='window.location = "${request.getContextPath()}/person/show/${person.id}"'>
+                            ${person.id}
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/person/show/${person.id}"'>
+                            ${person.loginName?.encodeAsHTML()}
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/person/show/${person.id}"'>
+                            ${person.firstName?.encodeAsHTML()}
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/person/show/${person.id}"'>
+                            ${person.lastName?.encodeAsHTML()}
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/person/show/${person.id}"'>
+                            ${person.isActive?.encodeAsHTML()}
+                        </td>
+
+                        <td class="notClickable">
+                            <g:link action="show" id="${person.id}">
+                                <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                            </g:link>
+                        </td>
+                    </tr>
+                </g:each>
+                </tbody>
+                </table>
+            </div>
+        </g:if>
+
+        <div class="paginateButtons">
+            <g:paginate total="${personTotal}" params="${filterParams}" />
+        </div>
+
+        <filterpane:filterPane domainBean="Person"
+                                title="Search"
+                                action="list"
+                                class="overlayPane"
+                                excludeProperties="password, sessionTimeout"
+                                associatedProperties="authorities.authority, personGroups.name"
+                                    filterPropertyValues="${['personGroups.name':[values:PersonGroup.list()],
+                                                                                'authorities.authority':[values:Authority.list()]]}" />
+
+
+    </div> <!-- end body div -->
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/person/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/person/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/person/show.gsp	(revision 875)
@@ -0,0 +1,143 @@
+<head>
+    <meta name="layout" content="main" />
+    <title>Show Person</title>
+    <nav:resources override="true"/>
+</head>
+
+<body>
+
+    <div class="nav">
+        <nav:renderSubItems group="navAlt"/>
+    </div>
+
+    <div class="body">
+        <g:render template="/shared/messages" />
+        <div class="dialog">
+            <table>
+            <tbody>
+
+                <tr class="prop">
+                    <td valign="top" class="name">ID:</td>
+                    <td valign="top" class="value">${person.id}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Login Name:</td>
+                    <td valign="top" class="value">${person.loginName?.encodeAsHTML()}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">First Name:</td>
+                    <td valign="top" class="value">${person.firstName?.encodeAsHTML()}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Last Name:</td>
+                    <td valign="top" class="value">${person.lastName?.encodeAsHTML()}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Active:</td>
+                    <td valign="top" class="value">${person.isActive}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Description:</td>
+                    <td valign="top" class="value">${person.description?.encodeAsHTML()}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Contact:</td>
+
+                    <td  valign="top" class="value">
+                        <ul>
+                        <g:each var="i" in="${person.contacts}">
+                            <li><g:link controller="contactDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                        </g:each>
+                        </ul>
+                    </td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Addresses:</td>
+
+                    <td  valign="top" class="value">
+                        <ul>
+                        <g:each var="i" in="${person.addresses}">
+                            <li><g:link controller="addressDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                        </g:each>
+                        </ul>
+                    </td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Employee ID:</td>
+                    <td valign="top" class="value">${person.employeeID}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Department:</td>
+                    <td valign="top" class="value">${person.department}</td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Groups:</td>
+                    <td valign="top" class="value">
+                        <ul>
+                        <g:each var='group' in="${ person.personGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                            <li>
+                                <g:link controller="personGroupDetailed"
+                                                action="show"
+                                                id="${group.id}">
+                                    ${group.encodeAsHTML()}
+                                </g:link>
+                            </li>
+                        </g:each>
+                        </ul>
+                    </td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Purchasing Groups:</td>
+                    <td valign="top" class="value">
+                        <ul>
+                        <g:each  var='a' in="${ person.purchasingGroups.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                            <li>
+                                <g:link controller="purchasingGroupDetailed"
+                                                action="show"
+                                                id="${a.id}">
+                                    ${a.encodeAsHTML()}
+                                </g:link>
+                            </li>
+                        </g:each>
+                        </ul>
+                    </td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Authorities:</td>
+                    <td valign="top" class="value">
+                        <ul>
+                        <g:each  var='a' in="${authorityList}">
+                            <li>${a.description.encodeAsHTML()}</li>
+                        </g:each>
+                        </ul>
+                    </td>
+                </tr>
+
+            </tbody>
+            </table>
+        </div>
+
+        <div class="buttons">
+            <g:form>
+                <input type="hidden" name="id" value="${person.id}" />
+                <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+            </g:form>
+        </div>
+
+    </div>
+</body>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/create.gsp	(revision 875)
@@ -0,0 +1,73 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create PersonGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${personGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${personGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:personGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:personGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${personGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="personGroupType">Person Group Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'personGroupType','errors')}">
+                                    <g:select optionKey="id" from="${PersonGroupType.list()}" name="personGroupType.id" value="${personGroupInstance?.personGroupType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit PersonGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${personGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${personGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${personGroupInstance?.id}" />
+                <input type="hidden" name="version" value="${personGroupInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:personGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:personGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${personGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="personGroupType">Person Group Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupInstance,field:'personGroupType','errors')}">
+                                    <g:select optionKey="id" from="${PersonGroupType.list()}" name="personGroupType.id" value="${personGroupInstance?.personGroupType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/list.gsp	(revision 875)
@@ -0,0 +1,71 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>PersonGroup List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                            <g:sortableColumn property="personGroupType" title="Group Type" />
+
+                            <th></th>
+                   	    
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${personGroupInstanceList}" status="i" var="personGroupInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupDetailed/show/${personGroupInstance.id}"'>
+                                ${fieldValue(bean:personGroupInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupDetailed/show/${personGroupInstance.id}"'>
+                                ${fieldValue(bean:personGroupInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupDetailed/show/${personGroupInstance.id}"'>
+                                ${fieldValue(bean:personGroupInstance, field:'isActive')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupDetailed/show/${personGroupInstance.id}"'>
+                                ${fieldValue(bean:personGroupInstance, field:'personGroupType')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${personGroupInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${personGroupInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupDetailed/show.gsp	(revision 875)
@@ -0,0 +1,83 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show PersonGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Person Group Type:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="personGroupTypeDetailed" action="show" id="${personGroupInstance?.personGroupType?.id}">${personGroupInstance?.personGroupType?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Persons:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="p" in="${personGroupInstance.persons}">
+                                    <li><g:link controller="person" action="show" id="${p.id}">${p?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${personGroupInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create PersonGroupType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${personGroupTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${personGroupTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:personGroupTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:personGroupTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${personGroupTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit PersonGroupType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${personGroupTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${personGroupTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${personGroupTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${personGroupTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:personGroupTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:personGroupTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${personGroupTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="personGroups">Person Groups:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:personGroupTypeInstance,field:'personGroups','errors')}">
+                                    
+<ul>
+<g:each var="p" in="${personGroupTypeInstance?.personGroups?}">
+    <li><g:link controller="personGroupDetailed" action="show" id="${p.id}">${p?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="personGroupDetailed" params="['personGroupType.id':personGroupTypeInstance?.id]" action="create">+Add PersonGroup</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/list.gsp	(revision 875)
@@ -0,0 +1,71 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>PersonGroupType List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${personGroupTypeInstanceList}" status="i" var="personGroupTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupTypeDetailed/show/${personGroupTypeInstance.id}"'>
+                                ${fieldValue(bean:personGroupTypeInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupTypeDetailed/show/${personGroupTypeInstance.id}"'>
+                                ${fieldValue(bean:personGroupTypeInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupTypeDetailed/show/${personGroupTypeInstance.id}"'>
+                                ${fieldValue(bean:personGroupTypeInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/personGroupTypeDetailed/show/${personGroupTypeInstance.id}"'>
+                                ${fieldValue(bean:personGroupTypeInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${personGroupTypeInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${personGroupTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/personGroupTypeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,76 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show PersonGroupType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:personGroupTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Person Groups:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="p" in="${personGroupTypeInstance.personGroups}">
+                                    <li><g:link controller="personGroupDetailed" action="show" id="${p.id}">${p?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${personGroupTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/create.gsp	(revision 875)
@@ -0,0 +1,49 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Create Picture</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Picture</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${picture}">
+                <div class="errors">
+                    <g:renderErrors bean="${picture}" as="list" />
+                </div>
+            </g:hasErrors>
+            <g:uploadForm action="save" onsubmit="return Lightbox.loading();">
+                <g:hiddenField name="inventoryItem.id" value="${picture.inventoryItem.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItem.id">Inventory Item:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    ${picture.inventoryItem}
+                                </td>
+                            </tr> 
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="file">File:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean: picture, field: 'file', 'errors')}">
+                                    <input type="file" id="file" name="file" size="40"/>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:uploadForm>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,66 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Edit Picture</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Picture</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${picture}">
+                <div class="errors">
+                    <g:renderErrors bean="${picture}" as="list" />
+                </div>
+            </g:hasErrors>
+            <g:form method="post" onsubmit="return Lightbox.loading();">
+                <input type="hidden" name="id" value="${picture?.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                            <tr class="prop">
+                                <td valign="top" class="name">Picture:</td>
+                                <td valign="top" class="value">
+                                    <span class='gallery'><wa:pictureLightboxAnchor picture="${picture}" size="${Image.Medium}" lightboxSize="${Image.Large}" title="Slide Show" /></span>
+                                </td>
+                            </tr>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="operation">Operation:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean: picture, field: 'operation', 'errors')}">
+                                    <select id="operation" name="operation">
+                                        <option value="${Picture.NoOp}" selected="selected">None</option>
+                                        <option value="${Picture.RotateClockWise90}">Rotate clockwise 90 degrees</option>
+                                        <option value="${Picture.RotateAntiClockWise90}">Rotate anti-clockwise 90 degrees</option>
+                                        <option value="${Picture.Rotate180}">Rotate 180 degrees</option>
+                                        <option value="${Picture.Flip}">Vertical mirror image</option>
+                                        <option value="${Picture.Flop}">Horizontal mirror image</option>
+                                    </select>
+                                </td>
+                            </tr>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryItem.id">Inventory Item:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:link controller="inventoryItemDetailed" action="show" id="${picture.inventoryItem?.id}" title="Show Inventory Item">
+                                        ${picture.inventoryItem?.toString()?.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/list.gsp	(revision 875)
@@ -0,0 +1,64 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Picture List</title>
+        <nav:resources override="true"/>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Picture List</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                            <th>Picture</th>
+                            <g:sortableColumn property="inventoryItem" title="Inventory Item" />
+                            <g:sortableColumn property="dateCreated" title="Date Created" />
+                            <g:sortableColumn property="lastUpdated" title="Last Updated" />
+                            <th></th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        <g:each in="${list}" status="i" var="picture">
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                                <td class="notClickable">
+                                    <wa:pictureLightboxAnchor picture="${picture}"
+                                                                                        size="${Image.Small}"
+                                                                                        lightboxSize="${Image.Large}"
+                                                                                        target="_blank" title="Show Original" />
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/pictureDetailed/show/${picture.id}"' >
+                                    <g:link controller="inventoryItemDetailed" action="show" id="${picture.inventoryItem?.id}" title="Show Inventory Item">
+                                        ${picture.inventoryItem?.toString()?.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/pictureDetailed/show/${picture.id}"' >
+                                    <g:formatDate format="EEE, dd-MMM-yyyy" date="${picture.dateCreated}"/>
+                                </td>
+
+                                <td onclick='window.location = "${request.getContextPath()}/pictureDetailed/show/${picture.id}"' >
+                                    <g:formatDate format="EEE, dd-MMM-yyyy" date="${picture.lastUpdated}"/>
+                                </td>
+
+                                <td class="notClickable">
+                                    <g:link action="show" id="${picture.id}">
+                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                    </g:link>
+                                </td>
+                            </tr>
+                        </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${paginateCount}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/pictureDetailed/show.gsp	(revision 875)
@@ -0,0 +1,54 @@
+<html>
+    <head>
+        <meta name="layout" content="main" />
+        <title>Show Picture</title>
+        <g:render template="/shared/pictureHead" />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Picture</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+                        <tr class="prop">
+                            <td valign="top" class="name">Picture:</td>
+                            <td valign="top" class="value">
+                                <span class='gallery'><wa:pictureLightboxAnchor picture="${picture}" size="${Image.Medium}" lightboxSize="${Image.Large}" target="_blank" title="Show Original" /></span>
+                            </td>
+                        </tr>
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Item:</td>
+                            <td valign="top" class="value"><g:link controller="inventoryItemDetailed" action="show" id="${picture.inventoryItem?.id}" title="Show Inventory Item">${picture.inventoryItem?.toString()?.encodeAsHTML()}</g:link></td>
+                        </tr>
+                        <tr class="prop">
+                            <td valign="top" class="name">Height:</td>
+                            <td valign="top" class="value">${picture.height}</td>
+                        </tr>
+                        <tr class="prop">
+                            <td valign="top" class="name">Width:</td>
+                            <td valign="top" class="value">${picture.width}</td>
+                        </tr>
+                        <tr class="prop">
+                            <td valign="top" class="name">Date Created:</td>
+                            <td valign="top" class="value"><g:formatDate format="EEE, dd-MMM-yyyy" date="${picture.dateCreated}"/></td>
+                        </tr>
+                        <tr class="prop">
+                            <td valign="top" class="name">Last Updated:</td>
+                            <td valign="top" class="value"><g:formatDate format="EEE, dd-MMM-yyyy" date="${picture.lastUpdated}"/></td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${picture?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/create.gsp	(revision 875)
@@ -0,0 +1,62 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create ProductionReference</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${productionReferenceInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${productionReferenceInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:productionReferenceInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:productionReferenceInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:productionReferenceInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="75" id="description" name="description" value="${fieldValue(bean:productionReferenceInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:productionReferenceInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${productionReferenceInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,66 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit ProductionReference</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${productionReferenceInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${productionReferenceInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${productionReferenceInstance?.id}" />
+                <input type="hidden" name="version" value="${productionReferenceInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:productionReferenceInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:productionReferenceInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:productionReferenceInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="75" id="description" name="description" value="${fieldValue(bean:productionReferenceInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:productionReferenceInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${productionReferenceInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/list.gsp	(revision 875)
@@ -0,0 +1,69 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>ProductionReference List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${productionReferenceInstanceList}" status="i" var="productionReferenceInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/productionReferenceDetailed/show/${productionReferenceInstance.id}"'>
+                                ${fieldValue(bean:productionReferenceInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/productionReferenceDetailed/show/${productionReferenceInstance.id}"'>
+                                ${fieldValue(bean:productionReferenceInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/productionReferenceDetailed/show/${productionReferenceInstance.id}"'>
+                                ${fieldValue(bean:productionReferenceInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/productionReferenceDetailed/show/${productionReferenceInstance.id}"'>
+                                ${fieldValue(bean:productionReferenceInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${productionReferenceInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${productionReferenceInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/productionReferenceDetailed/show.gsp	(revision 875)
@@ -0,0 +1,61 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show ProductionReference</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:productionReferenceInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:productionReferenceInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:productionReferenceInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:productionReferenceInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${productionReferenceInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/create.gsp	(revision 875)
@@ -0,0 +1,62 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create PurchasingGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${purchasingGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${purchasingGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:purchasingGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:purchasingGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${purchasingGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,66 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit PurchasingGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${purchasingGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${purchasingGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${purchasingGroupInstance?.id}" />
+                <input type="hidden" name="version" value="${purchasingGroupInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:purchasingGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:purchasingGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:purchasingGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${purchasingGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/list.gsp	(revision 875)
@@ -0,0 +1,69 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>PurchasingGroup List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${purchasingGroupInstanceList}" status="i" var="purchasingGroupInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/purchasingGroupDetailed/show/${purchasingGroupInstance.id}"'>
+                                ${fieldValue(bean:purchasingGroupInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${purchasingGroupInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${purchasingGroupInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/purchasingGroupDetailed/show.gsp	(revision 875)
@@ -0,0 +1,89 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show PurchasingGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:purchasingGroupInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Cost Codes:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${purchasingGroupInstance.costCodes}">
+                                    <li><g:link controller="costCodeDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                                <g:link controller="costCodeDetailed" params="['purchasingGroup.id':purchasingGroupInstance?.id]" action="create">+Add Cost Code</g:link>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Persons:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${purchasingGroupInstance.persons}">
+                                    <li><g:link controller="person" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                                <g:link controller="person" action="list">+Add Person</g:link>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${purchasingGroupInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/report/equipmentRegisterOhs.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/report/equipmentRegisterOhs.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/report/equipmentRegisterOhs.gsp	(revision 875)
@@ -0,0 +1,64 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Equipment Register (OH&amp;S) Report</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <h1>Equipment Register (OH&amp;S) Report</h1>
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <g:jasperForm controller="report"
+                                                    action="equipmentRegisterOhs"
+                                                    jasper="equipmentRegisterOhs"
+                                                    name="Equipment Register (OH&amp;S)">
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Date:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <richui:dateChooser name="startDate" id="equipmentRegisterOhs_startDate" format="dd-MM-yyyy" value="${new Date()-7}" />
+                                    to
+                                    <richui:dateChooser name="endDate" id="equipmentRegisterOhs_endDate" format="dd-MM-yyyy" value="${new Date()}" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Section:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:select optionKey="id"
+                                                        from="${Section.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="section.id">
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Report:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:jasperButtons jasper="equipmentRegisterOhs" format="PDF, XLS" text="PDF" />
+                                </td>
+                            </tr>
+
+                        </g:jasperForm>
+
+                    </tbody>
+                </table>
+            </div> <!--End dialog-->
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/report/inventoryValueDetailed.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/report/inventoryValueDetailed.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/report/inventoryValueDetailed.gsp	(revision 875)
@@ -0,0 +1,82 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Inventory Detailed Value Report</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <h1>Inventory Detailed Value Report</h1>
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <g:jasperForm controller="report"
+                                                    action="inventoryValueDetailed"
+                                                    jasper="inventoryValueDetailed"
+                                                    name="Inventory Value Detailed">
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Site:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:select optionKey="id"
+                                                        from="${Site.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="site.id">
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Inventory Types:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:checkBoxList name="inventoryTypes"
+                                                                            from="${InventoryType.findAllByIsActive(true)}"
+                                                                            optionKey="id"
+                                                                            sortBy="name"
+                                                                            linkController="inventoryTypeDetailed"
+                                                                            linkAction="show"
+                                                                            height="150px"/>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Inventory Groups:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:checkBoxList name="inventoryGroups"
+                                                                            from="${InventoryGroup.findAllByIsActive(true)}"
+                                                                            optionKey="id"
+                                                                            sortBy="name"
+                                                                            linkController="inventoryGroupDetailed"
+                                                                            linkAction="show"
+                                                                            height="150px"/>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Report:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:jasperButtons jasper="inventoryValueDetailed" format="PDF, XLS" text="PDF" />
+                                </td>
+                            </tr>
+
+                        </g:jasperForm>
+
+                    </tbody>
+                </table>
+            </div> <!--End dialog-->
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/report/inventoryValueOverview.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/report/inventoryValueOverview.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/report/inventoryValueOverview.gsp	(revision 875)
@@ -0,0 +1,82 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Inventory Overview Value Report</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <h1>Inventory Overview Value Report</h1>
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <g:jasperForm controller="report"
+                                                    action="inventoryValueOverview"
+                                                    jasper="inventoryValueOverview"
+                                                    name="Inventory Value Overview">
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Site:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:select optionKey="id"
+                                                        from="${Site.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="site.id">
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Inventory Types:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:checkBoxList name="inventoryTypes"
+                                                                            from="${InventoryType.findAllByIsActive(true)}"
+                                                                            optionKey="id"
+                                                                            sortBy="name"
+                                                                            linkController="inventoryTypeDetailed"
+                                                                            linkAction="show"
+                                                                            height="150px"/>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Inventory Groups:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:checkBoxList name="inventoryGroups"
+                                                                            from="${InventoryGroup.findAllByIsActive(true)}"
+                                                                            optionKey="id"
+                                                                            sortBy="name"
+                                                                            linkController="inventoryGroupDetailed"
+                                                                            linkAction="show"
+                                                                            height="150px"/>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Report:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:jasperButtons jasper="inventoryValueOverview" format="PDF, XLS" text="PDF" />
+                                </td>
+                            </tr>
+
+                        </g:jasperForm>
+
+                    </tbody>
+                </table>
+            </div> <!--End dialog-->
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/report/mandatoryRequirements.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/report/mandatoryRequirements.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/report/mandatoryRequirements.gsp	(revision 875)
@@ -0,0 +1,64 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Mandatory Requirements Report</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <h1>Mandatory Requirements Report</h1>
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <g:jasperForm controller="report"
+                                                    action="mandatoryRequirements"
+                                                    jasper="mandatoryRequirements"
+                                                    name="Mandatory Requirements">
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Date:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <richui:dateChooser name="startDate" id="startDate" format="dd-MM-yyyy" value="${new Date()-7}" />
+                                    to
+                                    <richui:dateChooser name="endDate" id="endDate" format="dd-MM-yyyy" value="${new Date()}" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Section:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:select optionKey="id"
+                                                        from="${Section.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="section.id">
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Report:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:jasperButtons jasper="mandatoryRequirements" format="PDF, XLS" text="PDF" />
+                                </td>
+                            </tr>
+
+                        </g:jasperForm>
+
+                    </tbody>
+                </table>
+            </div> <!--End dialog-->
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/report/regulatoryRequirements.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/report/regulatoryRequirements.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/report/regulatoryRequirements.gsp	(revision 875)
@@ -0,0 +1,64 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Regulatory Requirements Report</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <h1>Regulatory Requirements Report</h1>
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                        <g:jasperForm controller="report"
+                                                    action="regulatoryRequirements"
+                                                    jasper="regulatoryRequirements"
+                                                    name="Regulatory Requirements">
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Date:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <richui:dateChooser name="startDate" id="startDate" format="dd-MM-yyyy" value="${new Date()-7}" />
+                                    to
+                                    <richui:dateChooser name="endDate" id="endDate" format="dd-MM-yyyy" value="${new Date()}" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Section:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <g:select optionKey="id"
+                                                        from="${Section.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="section.id">
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Report:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:jasperButtons jasper="regulatoryRequirements" format="PDF, XLS" text="PDF" />
+                                </td>
+                            </tr>
+
+                        </g:jasperForm>
+
+                    </tbody>
+                </table>
+            </div> <!--End dialog-->
+        </div> <!--End body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/create.gsp	(revision 875)
@@ -0,0 +1,95 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Section</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${sectionInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${sectionInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:sectionInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:sectionInstance,field:'description')}"/>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:sectionInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${sectionInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="department">Department:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'department','errors')}">
+                                    <g:select optionKey="id" from="${Department.list()}" name="department.id" value="${sectionInstance?.department?.id}" ></g:select>
+                                    <p>
+                                        <g:link controller="departmentDetailed" action="create">+Add Department</g:link>
+                                    </p>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="site">Site:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'site','errors')}">
+                                    <g:select optionKey="id" from="${Site.list()}" name="site.id" value="${sectionInstance?.site?.id}" ></g:select>
+                                    <p>
+                                        <g:link controller="siteDetailed" action="create">+Add Site</g:link>
+                                    </p>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,144 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Section</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${sectionInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${sectionInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${sectionInstance?.id}" />
+                <input type="hidden" name="version" value="${sectionInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:sectionInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:sectionInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:sectionInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${sectionInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="assets">Assets:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'assets','errors')}">
+                                    
+<ul>
+<g:each var="a" in="${sectionInstance?.assets?}">
+    <li><g:link controller="assetDetailed" action="show" id="${a.id}">${a?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="assetDetailed" params="['section.id':sectionInstance?.id]" action="create">+Add Asset</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="department">Department:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'department','errors')}">
+                                    <g:select optionKey="id" from="${Department.list()}" name="department.id" value="${sectionInstance?.department?.id}" ></g:select>
+                                    <p>
+                                        <g:link controller="departmentDetailed" action="create">+Add Department</g:link>
+                                    </p>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="maintenanceActions">Maintenance Actions:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'maintenanceActions','errors')}">
+                                    
+<ul>
+<g:each var="m" in="${sectionInstance?.maintenanceActions?}">
+    <li><g:link controller="maintenanceActionDetailed" action="show" id="${m.id}">${m?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="maintenanceActionDetailed" params="['section.id':sectionInstance?.id]" action="create">+Add Maintenance Action</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="sectionExtendedAttributes">Section Extended Attributes:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'sectionExtendedAttributes','errors')}">
+                                    
+<ul>
+<g:each var="s" in="${sectionInstance?.sectionExtendedAttributes?}">
+    <li><g:link controller="sectionExtendedAttributeDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="sectionExtendedAttributeDetailed" params="['section.id':sectionInstance?.id]" action="create">+Add Extended Attribute</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="site">Site:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionInstance,field:'site','errors')}">
+                                    <g:select optionKey="id" from="${Site.list()}" name="site.id" value="${sectionInstance?.site?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/list.gsp	(revision 875)
@@ -0,0 +1,81 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Section List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                   	        <th>Department</th>
+                   	    
+                   	        <th>Site</th>
+
+                            <th></th>
+                   	    
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${sectionInstanceList}" status="i" var="sectionInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/sectionDetailed/show/${sectionInstance.id}"'>
+                                ${fieldValue(bean:sectionInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/sectionDetailed/show/${sectionInstance.id}"'>
+                                ${fieldValue(bean:sectionInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/sectionDetailed/show/${sectionInstance.id}"'>
+                                ${fieldValue(bean:sectionInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/sectionDetailed/show/${sectionInstance.id}"'>
+                                ${fieldValue(bean:sectionInstance, field:'isActive')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/sectionDetailed/show/${sectionInstance.id}"'>
+                                ${fieldValue(bean:sectionInstance, field:'department')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/sectionDetailed/show/${sectionInstance.id}"'>
+                                ${fieldValue(bean:sectionInstance, field:'site')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${sectionInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${sectionInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/sectionDetailed/show.gsp	(revision 875)
@@ -0,0 +1,121 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Section</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Comment:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionInstance, field:'comment')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Assets:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="a" in="${sectionInstance.assets}">
+                                    <li><g:link controller="assetDetailed" action="show" id="${a.id}">${a?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Department:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="departmentDetailed" action="show" id="${sectionInstance?.department?.id}">${sectionInstance?.department?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Maintenance Actions:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="m" in="${sectionInstance.maintenanceActions}">
+                                    <li><g:link controller="maintenanceActionDetailed" action="show" id="${m.id}">${m?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Section Extended Attributes:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="s" in="${sectionInstance.sectionExtendedAttributes}">
+                                    <li><g:link controller="sectionExtendedAttributeDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Site:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="siteDetailed" action="show" id="${sectionInstance?.site?.id}">${sectionInstance?.site?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${sectionInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,70 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create SectionExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Section Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${sectionExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${sectionExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:sectionExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${sectionExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${sectionExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="section">Section:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'section','errors')}">
+                                    <g:select optionKey="id" from="${Section.list()}" name="section.id" value="${sectionExtendedAttributeInstance?.section?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,74 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit SectionExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Section Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${sectionExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${sectionExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${sectionExtendedAttributeInstance?.id}" />
+                <input type="hidden" name="version" value="${sectionExtendedAttributeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:sectionExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${sectionExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${sectionExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="section">Section:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:sectionExtendedAttributeInstance,field:'section','errors')}">
+                                    <g:select optionKey="id" from="${Section.list()}" name="section.id" value="${sectionExtendedAttributeInstance?.section?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/sectionExtendedAttributeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,67 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show SectionExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Section Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionExtendedAttributeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Value:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionExtendedAttributeInstance, field:'value')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:sectionExtendedAttributeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Extended Attribute Type:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="extendedAttributeTypeDetailed" action="show" id="${sectionExtendedAttributeInstance?.extendedAttributeType?.id}">${sectionExtendedAttributeInstance?.extendedAttributeType?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Section:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="sectionDetailed" action="show" id="${sectionExtendedAttributeInstance?.section?.id}">${sectionExtendedAttributeInstance?.section?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${sectionExtendedAttributeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/shared/_assetTree.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/shared/_assetTree.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/shared/_assetTree.gsp	(revision 875)
@@ -0,0 +1,58 @@
+
+<div class="static_tree" >
+    ${assetInstance.encodeAsHTML()}
+    <g:link controller="assetSubItemDetailed" params="['asset.id':assetInstance?.id]" action="create">
+        <img src="${resource(dir:'images/skin',file:'database_add.png')}" alt="Add" title="Add Sub Item"/>
+    </g:link>
+    <g:link params="['assetToCopy.id':assetInstance?.id]" action="copy">
+        <img src="${resource(dir:'images/skin',file:'page_copy.png')}" alt="Copy" title="Copy Asset"/>
+    </g:link>
+
+    <ul>
+    <g:each var="assetSubItem1" in="${assetInstance.assetSubItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+        <li>
+            <a href='' class="toggle"
+                                onclick="showElement('treelevel1');
+                                                return false">
+            </a>
+            <g:link controller="assetSubItemDetailed" action="show" id="${assetSubItem1.id}">${assetSubItem1?.encodeAsHTML()}</g:link>
+            <g:link controller="assetSubItemDetailed" params="['parentItem.id':assetSubItem1?.id]" action="create">
+                <img src="${resource(dir:'images/skin',file:'database_add.png')}" alt="Add" title="Add Sub Item" />
+            </g:link>
+        </li>
+
+        <div id="treelevel1">
+
+            <ul>
+            <g:each var="assetSubItem2" in="${assetSubItem1.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                <li>
+                    <a href='' class="toggle">
+                    </a>
+                    <g:link controller="assetSubItemDetailed" action="show" id="${assetSubItem2.id}">${assetSubItem2?.encodeAsHTML()}</g:link>
+                    <g:link controller="assetSubItemDetailed" params="['parentItem.id':assetSubItem2?.id]" action="create">
+                        <img src="${resource(dir:'images/skin',file:'database_add.png')}" alt="Add" title="Add Sub Item" />
+                    </g:link>
+                </li>
+                <ul>
+                <g:each var="assetSubItem3" in="${assetSubItem2.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                    <li>
+                        <g:link controller="assetSubItemDetailed" action="show" id="${assetSubItem3.id}">${assetSubItem3?.encodeAsHTML()}</g:link>
+                        <g:link controller="assetSubItemDetailed" params="['parentItem.id':assetSubItem3?.id]" action="create">
+                            <img src="${resource(dir:'images/skin',file:'database_add.png')}" alt="Add" title="Add Sub Item" />
+                        </g:link>
+                    </li>
+                    <ul>
+                    <g:each var="assetSubItem4" in="${assetSubItem3.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                        <li><g:link controller="assetSubItemDetailed" action="show" id="${assetSubItem4.id}">${assetSubItem4?.encodeAsHTML()}</g:link></li>
+                    </g:each> <!--assetSubItem4-->
+                    </ul>
+                </g:each> <!--assetSubItem3-->
+                </ul>
+            </g:each> <!--assetSubItem2-->
+            </ul>
+
+        </div>
+
+    </g:each> <!--assetSubItem1-->
+    </ul>
+</div>
Index: /branches/features/grailsUpgrade/grails-app/views/shared/_assetTreeCompact.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/shared/_assetTreeCompact.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/shared/_assetTreeCompact.gsp	(revision 875)
@@ -0,0 +1,29 @@
+
+<%--  Fetch to prevent lazy initialization error.  --%>
+<% assetInstance = Asset.read(assetInstance?.id)%>
+
+<div class="static_tree">
+    ${assetInstance?.encodeAsHTML()}
+    <div class="static_tree_compact">
+        <ul>
+        <g:each var="assetSubItem1" in="${assetInstance?.assetSubItems?.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+            <li>
+                ${assetSubItem1?.encodeAsHTML()}
+            </li>
+
+            <div id="treelevel1">
+
+                <ul>
+                <g:each var="assetSubItem2" in="${assetSubItem1.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
+                    <li>
+                        ${assetSubItem2?.encodeAsHTML()}
+                    </li>
+                </g:each> <!--assetSubItem2-->
+                </ul>
+
+            </div>
+
+        </g:each> <!--assetSubItem1-->
+        </ul>
+    </div>
+</div>
Index: /branches/features/grailsUpgrade/grails-app/views/shared/_messages.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/shared/_messages.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/shared/_messages.gsp	(revision 875)
@@ -0,0 +1,12 @@
+<g:if test="${flash.message}">
+    <div class="message">${flash.message}</div>
+</g:if>
+<g:if test="${flash.errorMessage}">
+    <div class="message_error">${flash.errorMessage}</div>
+</g:if>
+<g:if test="${params.message}">
+    <div class="message">${params.message}</div>
+</g:if>
+<g:if test="${params.errorMessage}">
+    <div class="message_error">${params.errorMessage}</div>
+</g:if>
Index: /branches/features/grailsUpgrade/grails-app/views/shared/_pictureHead.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/shared/_pictureHead.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/shared/_pictureHead.gsp	(revision 875)
@@ -0,0 +1,4 @@
+
+<link rel="stylesheet" href="${resource(dir:'css',file:'lightbox.css')}" />
+<g:javascript library="lightbox" />
+<script type="text/javascript"> document.observe("dom:loaded", Lightbox.onload); </script>
Index: /branches/features/grailsUpgrade/grails-app/views/siteDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/siteDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/siteDetailed/create.gsp	(revision 875)
@@ -0,0 +1,71 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Site</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${siteInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${siteInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:siteInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:siteInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:siteInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${siteInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/siteDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/siteDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/siteDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,155 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Site</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${siteInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${siteInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${siteInstance?.id}" />
+                <input type="hidden" name="version" value="${siteInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'name','errors')}">
+                                    <input type="text" class="description" maxlength="50" id="name" name="name" value="${fieldValue(bean:siteInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'description','errors')}">
+                                    <input type="text" class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:siteInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:siteInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${siteInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="inventoryStores">Inventory Stores:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'inventoryStores','errors')}">
+                                    
+<ul>
+<g:each var="i" in="${siteInstance?.inventoryStores?}">
+    <li><g:link controller="inventoryStoreDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="inventoryStoreDetailed" params="['site.id':siteInstance?.id]" action="create">+Add Inventory Store</g:link>
+
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="addresses">Contact:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <ul>
+                                    <g:each var="i" in="${siteInstance?.contacts}">
+                                        <li><g:link controller="contactDetailed" action="show" id="${i.id}">
+                                            ${i?.encodeAsHTML()}
+                                        </g:link></li>
+                                    </g:each>
+                                    </ul>
+                                    <g:link controller="contactDetailed" params="['site.id':siteInstance?.id]" action="create">+Add Contact</g:link>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="addresses">Addresses:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'addresses','errors')}">
+                                    
+<ul>
+<g:each var="i" in="${siteInstance?.addresses?}">
+    <li><g:link controller="addressDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="addressDetailed" params="['site.id':siteInstance?.id]" action="create">+Add Address</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="sections">Sections:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'sections','errors')}">
+                                    
+<ul>
+<g:each var="s" in="${siteInstance?.sections?}">
+    <li><g:link controller="sectionDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="sectionDetailed" params="['site.id':siteInstance?.id]" action="create">+Add Section</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="siteExtendedAttributes">Site Extended Attributes:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteInstance,field:'siteExtendedAttributes','errors')}">
+                                    
+<ul>
+<g:each var="s" in="${siteInstance?.siteExtendedAttributes?}">
+    <li><g:link controller="siteExtendedAttributeDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="siteExtendedAttributeDetailed" params="['site.id':siteInstance?.id]" action="create">+Add Extended Attribute</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/siteDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/siteDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/siteDetailed/list.gsp	(revision 875)
@@ -0,0 +1,69 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Site List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${siteInstanceList}" status="i" var="siteInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/siteDetailed/show/${siteInstance.id}"'>
+                                ${fieldValue(bean:siteInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/siteDetailed/show/${siteInstance.id}"'>
+                                ${fieldValue(bean:siteInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/siteDetailed/show/${siteInstance.id}"'>
+                                ${fieldValue(bean:siteInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/siteDetailed/show/${siteInstance.id}"'>
+                                ${fieldValue(bean:siteInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${siteInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${siteInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/siteDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/siteDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/siteDetailed/show.gsp	(revision 875)
@@ -0,0 +1,133 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Site</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Comment:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteInstance, field:'comment')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Inventory Stores:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="i" in="${siteInstance.inventoryStores}">
+                                    <li><g:link controller="inventoryStoreDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Contact:</td>
+
+                            <td  valign="top" class="value">
+                                <ul>
+                                <g:each var="i" in="${siteInstance.contacts}">
+                                    <li><g:link controller="contactDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Addresses:</td>
+                            
+                            <td  valign="top" class="value">
+                                <ul>
+                                <g:each var="i" in="${siteInstance.addresses}">
+                                    <li><g:link controller="addressDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Sections:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="s" in="${siteInstance.sections}">
+                                    <li><g:link controller="sectionDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Site Extended Attributes:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="s" in="${siteInstance.siteExtendedAttributes}">
+                                    <li><g:link controller="siteExtendedAttributeDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${siteInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,70 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create SiteExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Site Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${siteExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${siteExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:siteExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${siteExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${siteExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="site">Site:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'site','errors')}">
+                                    <g:select optionKey="id" from="${Site.list()}" name="site.id" value="${siteExtendedAttributeInstance?.site?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,74 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit SiteExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Site Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${siteExtendedAttributeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${siteExtendedAttributeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${siteExtendedAttributeInstance?.id}" />
+                <input type="hidden" name="version" value="${siteExtendedAttributeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="value">Value:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'value','errors')}">
+                                    <input type="text" maxlength="100" id="value" name="value" value="${fieldValue(bean:siteExtendedAttributeInstance,field:'value')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${siteExtendedAttributeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="extendedAttributeType">Extended Attribute Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'extendedAttributeType','errors')}">
+                                    <g:select optionKey="id" from="${ExtendedAttributeType.list()}" name="extendedAttributeType.id" value="${siteExtendedAttributeInstance?.extendedAttributeType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="site">Site:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:siteExtendedAttributeInstance,field:'site','errors')}">
+                                    <g:select optionKey="id" from="${Site.list()}" name="site.id" value="${siteExtendedAttributeInstance?.site?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/siteExtendedAttributeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,67 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show SiteExtendedAttribute</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Site Extended Attribute</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteExtendedAttributeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Value:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteExtendedAttributeInstance, field:'value')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:siteExtendedAttributeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Extended Attribute Type:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="extendedAttributeTypeDetailed" action="show" id="${siteExtendedAttributeInstance?.extendedAttributeType?.id}">${siteExtendedAttributeInstance?.extendedAttributeType?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Site:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="siteDetailed" action="show" id="${siteExtendedAttributeInstance?.site?.id}">${siteExtendedAttributeInstance?.site?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${siteExtendedAttributeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/create.gsp	(revision 875)
@@ -0,0 +1,73 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Supplier</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${supplierInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${supplierInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:supplierInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:supplierInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${supplierInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="supplierType">Supplier Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'supplierType','errors')}">
+                                    <g:select optionKey="id" from="${SupplierType.list()}" name="supplierType.id" value="${supplierInstance?.supplierType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,109 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Supplier</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${supplierInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${supplierInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${supplierInstance?.id}" />
+                <input type="hidden" name="version" value="${supplierInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:supplierInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:supplierInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${supplierInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="supplierType">Supplier Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierInstance,field:'supplierType','errors')}">
+                                    <g:select optionKey="id" from="${SupplierType.list()}" name="supplierType.id" value="${supplierInstance?.supplierType?.id}" ></g:select>
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="addresses">Contact:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <ul>
+                                    <g:each var="i" in="${supplierInstance?.contacts}">
+                                        <li><g:link controller="contactDetailed" action="show" id="${i.id}">
+                                            ${i?.encodeAsHTML()}
+                                        </g:link></li>
+                                    </g:each>
+                                    </ul>
+                                    <g:link controller="contactDetailed" params="['supplier.id':supplierInstance?.id]" action="create">+Add Contact</g:link>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="addresses">Addresses:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <ul>
+                                    <g:each var="i" in="${supplierInstance?.addresses?}">
+                                        <li><g:link controller="supplierDetailed" action="show" id="${i.id}">
+                                            ${i?.encodeAsHTML()}
+                                        </g:link></li>
+                                    </g:each>
+                                    </ul>
+                                    <g:link controller="addressDetailed" params="['supplier.id':supplierInstance?.id]" action="create">+Add Address</g:link>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/list.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Supplier List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                            <g:sortableColumn property="id" title="Id" />
+
+                            <g:sortableColumn property="name" title="Name" />
+
+                            <g:sortableColumn property="description" title="Description" />
+
+                            <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th>Supplier Type</th>
+                            
+                            <th></th>
+                   	    
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${supplierInstanceList}" status="i" var="supplierInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierDetailed/show/${supplierInstance.id}"'>
+                                ${fieldValue(bean:supplierInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierDetailed/show/${supplierInstance.id}"'>
+                                ${fieldValue(bean:supplierInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierDetailed/show/${supplierInstance.id}"'>
+                                ${fieldValue(bean:supplierInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierDetailed/show/${supplierInstance.id}"'>
+                                ${fieldValue(bean:supplierInstance, field:'isActive')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierDetailed/show/${supplierInstance.id}"'>
+                                ${fieldValue(bean:supplierInstance, field:'supplierType')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${supplierInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${supplierInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierDetailed/show.gsp	(revision 875)
@@ -0,0 +1,96 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Supplier</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Supplier Type:</td>
+                            
+                            <td valign="top" class="value"><g:link controller="supplierTypeDetailed" action="show" id="${supplierInstance?.supplierType?.id}">${supplierInstance?.supplierType?.encodeAsHTML()}</g:link></td>
+                            
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Contact:</td>
+
+                            <td  valign="top" class="value">
+                                <ul>
+                                <g:each var="i" in="${supplierInstance.contacts}">
+                                    <li><g:link controller="contactDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Addresses:</td>
+                            
+                            <td  valign="top" class="value">
+                                <ul>
+                                <g:each var="i" in="${supplierInstance.addresses}">
+                                    <li><g:link controller="addressDetailed" action="show" id="${i.id}">${i?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${supplierInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create SupplierType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${supplierTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${supplierTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:supplierTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:supplierTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${supplierTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit SupplierType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${supplierTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${supplierTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${supplierTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${supplierTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierTypeInstance,field:'name','errors')}">
+                                    <input type="text" id="name" name="name" value="${fieldValue(bean:supplierTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierTypeInstance,field:'description','errors')}">
+                                    <input type="text" id="description" name="description" value="${fieldValue(bean:supplierTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${supplierTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="suppliers">Suppliers:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:supplierTypeInstance,field:'suppliers','errors')}">
+                                    
+<ul>
+<g:each var="s" in="${supplierTypeInstance?.suppliers?}">
+    <li><g:link controller="supplierDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="supplierDetailed" params="['supplierType.id':supplierTypeInstance?.id]" action="create">+Add Supplier</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/list.gsp	(revision 875)
@@ -0,0 +1,71 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>SupplierType List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                            <g:sortableColumn property="id" title="Id" />
+
+                            <g:sortableColumn property="name" title="Name" />
+
+                            <g:sortableColumn property="description" title="Description" />
+
+                            <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${supplierTypeInstanceList}" status="i" var="supplierTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                            <td onclick='window.location = "${request.getContextPath()}/supplierTypeDetailed/show/${supplierTypeInstance.id}"'>
+                                ${fieldValue(bean:supplierTypeInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierTypeDetailed/show/${supplierTypeInstance.id}"'>
+                                ${fieldValue(bean:supplierTypeInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierTypeDetailed/show/${supplierTypeInstance.id}"'>
+                                ${fieldValue(bean:supplierTypeInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/supplierTypeDetailed/show/${supplierTypeInstance.id}"'>
+                                ${fieldValue(bean:supplierTypeInstance, field:'isActive')}
+                            </td>
+                            
+                            <td class="notClickable">
+                                <g:link action="show" id="${supplierTypeInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${supplierTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/supplierTypeDetailed/show.gsp	(revision 875)
@@ -0,0 +1,76 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show SupplierType</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:supplierTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Suppliers:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="s" in="${supplierTypeInstance.suppliers}">
+                                    <li><g:link controller="supplierDetailed" action="show" id="${s.id}">${s?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${supplierTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskBudgetStatus</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskBudgetStatus List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create TaskBudgetStatus</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskBudgetStatusInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskBudgetStatusInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskBudgetStatusInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskBudgetStatusInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskBudgetStatusInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskBudgetStatusInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskBudgetStatusInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskBudgetStatusInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskBudgetStatus</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskBudgetStatus List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskBudgetStatus</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit TaskBudgetStatus</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskBudgetStatusInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskBudgetStatusInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskBudgetStatusInstance?.id}" />
+                <input type="hidden" name="version" value="${taskBudgetStatusInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskBudgetStatusInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskBudgetStatusInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskBudgetStatusInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskBudgetStatusInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskBudgetStatusInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskBudgetStatusInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="tasks">Tasks:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskBudgetStatusInstance,field:'tasks','errors')}">
+                                    
+<ul>
+<g:each var="t" in="${taskBudgetStatusInstance?.tasks?}">
+    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="task" params="['taskBudgetStatus.id':taskBudgetStatusInstance?.id]" action="create">Add Task</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskBudgetStatus List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New TaskBudgetStatus</g:link></span>
+        </div>
+        <div class="body">
+            <h1>TaskBudgetStatus List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${taskBudgetStatusInstanceList}" status="i" var="taskBudgetStatusInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${taskBudgetStatusInstance.id}">${fieldValue(bean:taskBudgetStatusInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:taskBudgetStatusInstance, field:'name')}</td>
+                        
+                            <td>${fieldValue(bean:taskBudgetStatusInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:taskBudgetStatusInstance, field:'isActive')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${taskBudgetStatusInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskBudgetStatus/show.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskBudgetStatus</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskBudgetStatus List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskBudgetStatus</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show TaskBudgetStatus</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskBudgetStatusInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskBudgetStatusInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskBudgetStatusInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskBudgetStatusInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Tasks:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="t" in="${taskBudgetStatusInstance.tasks}">
+                                    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${taskBudgetStatusInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_list.gsp	(revision 875)
@@ -0,0 +1,153 @@
+    <g:if test="${taskInstanceList.size() > 0}">
+        <div class="list">
+            <table>
+                <thead>
+                    <tr>
+
+                        <custom:sortableColumnWithImg property="attentionFlag"
+                                                                                        imgSrc="${resource(dir:'images/skin',file:'flag_red.png')}"
+                                                                                        imgAlt="Flag"
+                                                                                        imgTitle="Attention Flag"
+                                                                                        params="${filterParams}" />
+
+                        <custom:sortableColumnWithImg property="highestSeverity"
+                                                                                        imgSrc="${resource(dir:'images/skin',file:'award_star_silver_3.png')}"
+                                                                                        imgAlt="Severity"
+                                                                                        imgTitle="Highest Severity"
+                                                                                        params="${filterParams}" />
+
+                        <g:sortableColumn property="targetStartDate" title="Target Start Date" params="${filterParams}" />
+
+                        <th>Description</th>
+
+                        <g:sortableColumn property="taskGroup" title="Group" params="${filterParams}" />
+
+                        <g:sortableColumn  property="taskType" title="Type" params="${filterParams}" />
+
+                        <custom:sortableColumnWithImg property="taskStatus"
+                                                                                        imgSrc="${resource(dir:'images/skin',file:'status.png')}"
+                                                                                        imgAlt="Status"
+                                                                                        imgTitle="Status"
+                                                                                        params="${filterParams}" />
+
+                        <g:sortableColumn  property="taskPriority" title="Priority" params="${filterParams}" />
+
+                        <custom:sortableColumnWithImg property="defaultSort"
+                                                                                        imgSrc="${resource(dir:'images/skin',file:'table_sort.png')}"
+                                                                                        imgAlt="Sort"
+                                                                                        imgTitle="Default Sort"
+                                                                                        params="${filterParams}" />
+
+                    </tr>
+                </thead>
+                <tbody>
+                <g:each in="${taskInstanceList}" status="i" var="taskInstance">
+                <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                        <td class="idColumn" onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            <g:if test="${taskInstance.attentionFlag}">
+                                <img  src="${resource(dir:'images/skin',file:'flag_red.png')}" alt="Flag" title="Attention Flag"/>
+                            </g:if>
+                        </td>
+
+                        <td class="idColumn" onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            <g:if test="${taskInstance.highestSeverity}">
+                                ${taskInstance.highestSeverity.code.encodeAsHTML()}
+                            </g:if>
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            <g:formatDate date="${taskInstance.targetStartDate}" format="EEE, dd-MMM-yyyy"/>
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            <b>
+                                Task #${fieldValue(bean:taskInstance, field:'id')}
+                            </b>
+                            <g:if test="${taskInstance.approved}" >
+                                <img  src="${resource(dir:'images/skin',file:'cog.png')}" alt="Approved" title="Approved" />
+                            </g:if>
+                            <g:if test="${taskInstance.taskRecurringSchedule?.enabled}" >
+                                <img  src="${resource(dir:'images/skin',file:'arrow_refresh.png')}" alt="Recurrence Enabled" title="Recurrence Enabled" />
+                            </g:if>
+                            <br />
+
+                            <b>
+                            <g:if test="${taskInstance.primaryAsset}">
+                                ${fieldValue(bean:taskInstance, field:'primaryAsset')}:
+                            </g:if>
+                            ${fieldValue(bean:taskInstance, field:'description')}
+                            </b>
+                            <g:if test="${taskInstance.taskProcedureRevision?.maintenanceActions}" >
+                                <br />
+                                <custom:taskProcedureMachines taskProcedureRevision="${taskInstance.taskProcedureRevision}" />
+                            </g:if>
+                            <g:if test="${taskInstance.safetyRequirement}" >
+                                <br />
+                                <img  src="${resource(dir:'images/skin',file:'lightning.png')}" alt="Safety Requirement" title="Safety Requirement" />
+                                Safety
+                            </g:if>
+                            <g:if test="${taskInstance.regulatoryRequirement}" >
+                                <br />
+                                <img  src="${resource(dir:'images/skin',file:'script_lightning.png')}" alt="Regulatory Requirement" title="Regulatory Requirement" />
+                                Regulatory
+                            </g:if>
+                            <g:if test="${taskInstance.mandatoryRequirement}" >
+                                <br />
+                                <img  src="${resource(dir:'images/skin',file:'script.png')}" alt="Mandatory Requirement" title="Mandatory Requirement" />
+                                Mandatory
+                            </g:if>
+                            <br />
+                            <br />
+                            <g:each in="${taskInstance.assignedGroups}" status="j" var="assignedGroup">
+                                ${assignedGroup.encodeAsHTML()}<br />
+                            </g:each>
+                            <g:each in="${taskInstance.assignedPersons}" status="k" var="assignedPerson">
+                                ${assignedPerson.encodeAsHTML()}<br />
+                            </g:each>
+                            <g:each in="${taskInstance.entries}" status="m" var="entry">
+                                <g:if test="${entry.entryType.id == 3}">
+                                    <em>${'WD: ' +entry.toShortString().encodeAsHTML()}</em><br />
+                                </g:if>
+                            </g:each>
+                            <g:if test="${taskInstance.subTasks}">
+                                Sub Tasks: ${taskInstance.subTasks.size()}<br />
+                            </g:if>
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            ${fieldValue(bean:taskInstance, field:'taskGroup')}
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            ${fieldValue(bean:taskInstance, field:'taskType')}
+                        </td>
+
+                        <td class="idColumn" onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            <g:if test="${taskInstance.taskStatus.id == 1}" >
+                                <img  src="${resource(dir:'images/skin',file:'not_started.png')}" alt="Not Started" title="Not Started" />
+                            </g:if>
+                            <g:if test="${taskInstance.taskStatus.id == 2}" >
+                                <img  src="${resource(dir:'images/skin',file:'arrow_right.png')}" alt="In Progress" title="In Progress" />
+                            </g:if>
+                            <g:if test="${taskInstance.taskStatus.id == 3}" >
+                                <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Complete" title="Complete" />
+                            </g:if>
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'>
+                            ${fieldValue(bean:taskInstance, field:'taskPriority')}
+                        </td>
+
+                        <td class="notClickable">
+                            <g:link action="show" id="${taskInstance.id}">
+                                <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" title="Show" />
+                            </g:link>
+                        </td>
+
+                    </tr>
+                </g:each>
+                </tbody>
+            </table>
+        </div>
+    </g:if>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_quickSearchPane.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_quickSearchPane.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_quickSearchPane.gsp	(revision 875)
@@ -0,0 +1,121 @@
+<!-- Start Search Pane -->
+<div class="overlayPane" id="searchPane" style="display:none;">
+    <h2>Quick Search</h2>
+
+    <g:form method="post" controller="taskDetailed">
+        <table>
+            <tbody>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Select:</td>
+                    <td valign="top" class="value">
+                        <g:select optionKey="key"
+                                            optionValue="value"
+                                            from="${quickSearchSelection}"
+                                            name="quickSearch"
+                                            id="quickSearchSelect"
+                                            value="${params.quickSearch}">
+                        </g:select>
+
+                            <span id="allTasksHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.all.tasks" />
+                            </span>
+                            <span id="personsTasksHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.persons.tasks" />
+                            </span>
+                            <span id="personsImmediateCalloutsHelp">
+                                <g:helpBalloon class="helpballoon" code="task.search.text.persons.immediate.callouts" />
+                            </span>
+                    </td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">
+                        <label for="date">Between:</label>
+                    </td>
+                    <td valign="top" class="value">
+                        <richui:dateChooser name="startDate" format="dd-MM-yyyy" value="${params.startDate}" />
+                        and
+                        <richui:dateChooser name="endDate" format="dd-MM-yyyy" value="${params.endDate}" />
+                    </td>
+                </tr>
+
+                <tr class="prop" style="height:2.7em;">
+                    <td valign="top" class="name">
+                        <label for="person.id" id="personLabel">Person:</label>
+                    </td>
+                    <td valign="top" class="value">
+                        <div id="personSelection">
+                            <g:select optionKey="id"
+                                                from="${Person.findAllByIsActive(true).sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                name="person.id"
+                                                value="${params.person?.id}"
+                                                id="personSelector">
+                            </g:select>
+                        </div>
+                    </td>
+                </tr>
+
+                <tr class="prop" style="height:2.7em;">
+                    <td valign="top" class="name">
+                        <label for="includeCompleted" id="completedLabel">Incl. Completed:</label>
+                    </td>
+                    <td valign="top" class="value">
+                        <div id="completedSelection">
+                            <g:checkBox name="includeCompleted"
+                                                    value="${params.includeCompleted}"
+                                                    id="completedSelector">
+                            </g:checkBox>
+                            <g:helpBalloon class="helpballoon" code="task.search.include.completed" />
+                        </div>
+                    </td>
+                </tr>
+
+            </tbody>
+        </table>
+
+        <div class="buttons">
+            <span class="button">
+                <g:actionSubmit class="save" value="Update" action="${actionName}" />
+                <g:actionSubmit class="cancel" value="${g.message(code:'fp.tag.filterPane.button.cancel.text', default:'Cancel')}" onclick="return hideElement('searchPane');" />
+            </span>
+        </div>
+    </g:form>
+
+    <table>
+        <tbody>
+            <tr class="prop">
+                <td valign="top" class="name">
+                    <label>My Tasks:</label>
+                </td>
+                <td valign="top" class="value">
+                    <g:link controller="taskDetailed"
+                                    action="${actionName}"
+                                    params="[quickSearch: 'myTodays']">
+                                    <g:message code="task.search.text.my.todays" />
+                    </g:link> - <g:message code="task.search.text.my.todays.description" />
+                    <br />
+                </td>
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">
+                    <label>Links:</label>
+                </td>
+                <td valign="top" class="value">
+                    <g:link controller="taskDetailed"
+                                    action="workDone">
+                                    <g:message code="task.search.text.work.done" />
+                    </g:link> - <g:message code="task.search.text.work.done.description" />
+                    <br />
+                    <g:link controller="taskDetailed"
+                                    action="workLoad">
+                                    <g:message code="task.search.text.work.load" />
+                    </g:link> - <g:message code="task.search.text.work.load.description" />
+                </td>
+            </tr>
+
+        </tbody>
+    </table>
+
+</div> <!-- end search pane -->
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showInventoryTab.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showInventoryTab.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showInventoryTab.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+    <g:if test="${inventoryMovementList.isEmpty()}">
+        <br />
+        No Inventory Movements.
+        <br />
+        <br />
+    </g:if>
+    <g:else>
+        <div class="list">
+            <table>
+                <thead>
+                    <tr>
+                        <th>Inventory Item</th>
+                        <th>Quantity</th>
+                        <th>Movement Type</th>
+                        <th>Date</th>
+                        <th></th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <g:each in="${inventoryMovementList}" status="i" var="inventoryMovementInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                ${fieldValue(bean:inventoryMovementInstance, field:'inventoryItem')}
+                            </td>
+
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                ${fieldValue(bean:inventoryMovementInstance, field:'quantity')}
+                            </td>
+
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                ${fieldValue(bean:inventoryMovementInstance, field:'inventoryMovementType')}
+                            </td>
+
+                            <td onclick='window.location = "${request.getContextPath()}/inventoryMovementDetailed/show/${inventoryMovementInstance.id}"'>
+                                <g:formatDate date="${inventoryMovementInstance.date}" format="EEE, dd-MMM-yyyy"/>
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link controller="inventoryMovementDetailed" action="show" id="${inventoryMovementInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" title="Show" />
+                                </g:link>
+                            </td>
+
+                        </tr>
+                    </g:each>
+                </tbody>
+            </table>
+        </div>
+    </g:else>
+
+    <g:form controller="inventoryItemDetailed" >
+        <g:hiddenField name="task.id" value="${taskInstance?.id}" />
+        <div class="buttons">
+            <g:if test="${!inventoryMovementList.isEmpty()}">
+                Results: ${inventoryMovementList.size()}
+                <br />
+            </g:if>
+            <span class="button">
+                <g:actionSubmit action="findInventoryItemForMovement" class="add" value="Add" />
+            </span>
+        </div>
+    </g:form>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showProcedureTab.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showProcedureTab.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showProcedureTab.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+    <g:if test="${!taskProcedureExits}">
+        <br />
+        No Procedure linked.
+        <br />
+        <br />
+        <g:form controller="taskProcedureDetailed" >
+            <g:hiddenField name="taskInstance.id" value="${taskInstance?.id}" />
+
+            <div class="buttons">
+                <span class="button">
+                    <g:actionSubmit value="New" action="create" class="add"/>
+                </span>
+                <span class="button">
+                    <g:actionSubmit value="Search" action="search" class="search"/>
+                </span>
+            </div>
+
+        </g:form>
+
+    </g:if>
+    <g:else>
+        <g:render template="/taskProcedureDetailed/taskProcedureRevision"
+                            model="['taskProcedureRevision':taskProcedureRevision]" />
+        <br />
+
+        <div id="pmEntryContainer">
+            <g:if test="${entryPMList.isEmpty()}">
+                <h1>No PM Entries</h1>
+                <br />
+            </g:if>
+            <g:else>
+                <g:render template="/entryDetailed/list"
+                                    model="['entryList':entryPMList]" />
+            </g:else>
+        </div>
+
+        <br />
+
+        <div id="createPMEntryContainer" style="display:none;"></div>
+
+        <div style="text-align:right;" id="pmEntryButton">
+            <span class="buttons">
+                <input type="button"
+                            class="add"
+                            value="Add PM Entry"
+                            onclick="getCreateEntryForm(jQuery('#pmEntryContainer'),
+                                                                                jQuery('#pmEntryButton'),
+                                                                                {target: '#createPMEntryContainer',
+                                                                                taskId: ${taskInstance?.id},
+                                                                                entryTypeId: 6})" />
+            </span>
+        </div>
+
+    </g:else>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showRecurrenceTab.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showRecurrenceTab.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showRecurrenceTab.gsp	(revision 875)
@@ -0,0 +1,87 @@
+
+    <g:if test="${!taskRecurringScheduleExits}">
+        <br />
+        No Recurring Schedule.
+        <br />
+        <br />
+        <g:form controller="taskRecurringScheduleDetailed" >
+            <g:hiddenField name="task.id" value="${taskInstance.id}" />
+
+            <div class="buttons">
+                <span class="button">
+                    <g:actionSubmit value="Add" action="create" class="add" />
+                </span>
+            </div>
+
+        </g:form>
+
+    </g:if>
+    <g:else>
+
+    <div class="dialog">
+            <table>
+                <tbody>
+                    <tr class="prop">
+                        <td valign="top" class="name">Recurring Schedule:</td>
+
+                        <td valign="top" class="value">${taskRecurringScheduleInstance.encodeAsHTML()}</td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Enabled:</td>
+
+                        <td valign="top" class="value">${fieldValue(bean:taskRecurringScheduleInstance, field:'enabled')}</td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Next Generation Date:</td>
+
+                        <td valign="top" class="value">
+                            <g:formatDate date="${taskRecurringScheduleInstance.nextGenerationDate}" format="EEE, dd-MMM-yyyy"/>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Generate Ahead:</td>
+
+                        <td valign="top" class="value">
+                            ${taskRecurringScheduleInstance?.generateAhead} ${Period.get(1).encodeAsHTML()}
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Next Target Start Date:</td>
+
+                        <td valign="top" class="value">
+                            <g:formatDate date="${taskRecurringScheduleInstance.nextTargetStartDate}" format="EEE, dd-MMM-yyyy"/>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Task Duration:</td>
+
+                        <td valign="top" class="value">
+                            ${taskRecurringScheduleInstance?.taskDuration} ${taskRecurringScheduleInstance?.taskDurationPeriod}
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Next Target Completion Date:</td>
+
+                        <td valign="top" class="value">
+                            <g:formatDate date="${taskRecurringScheduleInstance.nextTargetCompletionDate}" format="EEE, dd-MMM-yyyy"/>
+                        </td>
+                    </tr>
+
+                </tbody>
+            </table>
+        </div>
+        <div class="buttons">
+            <g:form controller="taskRecurringScheduleDetailed">
+                <input type="hidden" name="id" value="${taskRecurringScheduleInstance?.id}" />
+                <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                <span class="button"><g:actionSubmit class="go" value="Show" /></span>
+            </g:form>
+        </div>
+
+    </g:else>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showSubTaskTab.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showSubTaskTab.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showSubTaskTab.gsp	(revision 875)
@@ -0,0 +1,100 @@
+
+    <g:if test="${subTaskInstanceTotal > 0}">
+        <div class="list">
+            <table>
+                <thead>
+                    <tr>
+
+                        <th>Task #</th>
+
+                        <th>Target Start Date</th>
+
+                        <th>Description</th>
+
+                        <th>
+                            <img src="${resource(dir:'images/skin',file:'status.png')}" title="Status" alt="Status" />
+                        </th>
+
+                        <th>Priority</th>
+
+                        <th></th>
+
+                    </tr>
+                </thead>
+                <tbody>
+                <g:each in="${subTaskInstanceList}" status="i" var="subTaskInstance">
+                    <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${subTaskInstance.id}"'>
+                            ${fieldValue(bean:subTaskInstance, field:'id')}
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${subTaskInstance.id}"'>
+                            <g:formatDate date="${subTaskInstance.targetStartDate}" format="EEE, dd-MMM-yyyy"/>
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${subTaskInstance.id}"'>
+                            <g:if test="${subTaskInstance.primaryAsset}">
+                                ${fieldValue(bean:subTaskInstance, field:'primaryAsset')}:
+                            </g:if>
+                            ${fieldValue(bean:subTaskInstance, field:'description')}
+                        </td>
+
+                        <td class="idColumn" onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${subTaskInstance.id}"'>
+                            <g:if test="${subTaskInstance.taskStatus.id == 1}" >
+                                <img  src="${resource(dir:'images/skin',file:'not_started.png')}" alt="Not Started" title="Not Started" />
+                            </g:if>
+                            <g:if test="${subTaskInstance.taskStatus.id == 2}" >
+                                <img  src="${resource(dir:'images/skin',file:'arrow_right.png')}" alt="In Progress" title="In Progress" />
+                            </g:if>
+                            <g:if test="${subTaskInstance.taskStatus.id == 3}" >
+                                <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Complete" title="Complete" />
+                            </g:if>
+                        </td>
+
+                        <td onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${subTaskInstance.id}"'>
+                            ${fieldValue(bean:subTaskInstance, field:'taskPriority')}
+                        </td>
+
+                        <td class="notClickable">
+                            <g:link action="show" id="${subTaskInstance.id}">
+                                <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" title="Show" />
+                            </g:link>
+                        </td>
+
+                    </tr>
+                </g:each>
+                </tbody>
+            </table>
+        </div>
+
+        <div class="buttons">
+            <g:form>
+                <g:hiddenField name="id" value="${taskInstance?.id}" />
+                <g:if test="${subTaskInstanceTotal > subTaskInstanceMax}">
+                    Showing ${subTaskInstanceMax} of ${subTaskInstanceTotal}
+                    <br />
+                </g:if>
+                <g:else>
+                    Total ${subTaskInstanceTotal}
+                    <br />
+                </g:else>
+                <span class="button"><g:actionSubmit action="listSubTasks" class="table" value="List" /></span>
+                <span class="button"><g:actionSubmit action="createSubTask" class="save" value="Create" onclick="return confirm('${g.message(code: 'sub.task.create.confirm')}');" /></span>
+            </g:form>
+        </div>
+
+    </g:if>
+    <g:else>
+        <br />
+        No Sub Tasks.
+        <br />
+        <br />
+
+        <div class="buttons">
+            <g:form>
+                <g:hiddenField name="id" value="${taskInstance?.id}" />
+                <span class="button"><g:actionSubmit action="createSubTask" class="save" value="Create" onclick="return confirm('${g.message(code: 'sub.task.create.confirm')}');" /></span>
+            </g:form>
+        </div>
+    </g:else>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTabHeader.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTabHeader.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTabHeader.gsp	(revision 875)
@@ -0,0 +1,36 @@
+
+    <h1>
+        Task #${taskInstance.id}
+
+        <g:if test="${taskInstance.approved}" >
+            <img  src="${resource(dir:'images/skin',file:'cog.png')}" alt="Approved" title="Approved" />
+        </g:if>
+        <g:if test="${taskRecurringScheduleInstance?.enabled}" >
+            <img  src="${resource(dir:'images/skin',file:'arrow_refresh.png')}" alt="Recurrence Enabled" title="Recurrence Enabled" />
+        </g:if>
+        <g:if test="${taskInstance.taskStatus.id == 2}" >
+            <img  src="${resource(dir:'images/skin',file:'arrow_right.png')}" alt="In Progress" title="In Progress" />
+        </g:if>
+        <g:if test="${taskInstance.attentionFlag}" >
+            <img  src="${resource(dir:'images/skin',file:'flag_red.png')}" alt="Attention Flag" title="Attention Flag" />
+        </g:if>
+        <g:if test="${taskInstance.taskStatus.id == 3}" >
+            <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Complete" title="Complete" />
+        </g:if>
+    </h1>
+    <g:if test="${taskInstance.primaryAsset}" >
+        ${fieldValue(bean:taskInstance, field:'primaryAsset')}:
+    </g:if>
+    ${fieldValue(bean:taskInstance, field:'description')}
+    <g:if test="${taskInstance.safetyRequirement}" >
+        <img  src="${resource(dir:'images/skin',file:'lightning.png')}" alt="Safety Requirement" title="Safety Requirement" />
+        Safety
+    </g:if>
+    <g:if test="${taskInstance.regulatoryRequirement}" >
+        <img  src="${resource(dir:'images/skin',file:'script_lightning.png')}" alt="Regulatory Requirement" title="Regulatory Requirement" />
+        Regulatory
+    </g:if>
+    <g:if test="${taskInstance.mandatoryRequirement}" >
+        <img  src="${resource(dir:'images/skin',file:'script.png')}" alt="Mandatory Requirement" title="Mandatory Requirement" />
+        Mandatory
+    </g:if>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskControlButtons.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskControlButtons.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskControlButtons.gsp	(revision 875)
@@ -0,0 +1,57 @@
+
+    <g:form controller="taskDetailed">
+        <input type="hidden" name="id" value="${taskInstance?.id}" />
+
+        <g:if test="${taskInstance.trash}" >
+            <span class="button">
+                <g:actionSubmit class="restore" onclick="return confirm('Are you sure?');" value="Restore"/>
+            </span>
+        </g:if>
+        <g:else>
+
+            <g:if test="${taskInstance.taskStatus.id != 3}" >
+
+                <g:if test="${taskInstance.attentionFlag}" >
+                    <span class="button"><g:actionSubmit class="flag" value="Clear" action="clearAttentionFlag"/></span>
+                </g:if>
+                <g:else>
+                    <span class="button"><g:actionSubmit class="flag" value="Unresolved" action="setAttentionFlag"/></span>
+                    <custom:helpBalloon code="task.status.unresolved" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+
+                </g:else>
+
+                <span class="button">
+                    <g:if test="${taskInstance.attentionFlag}" >
+                        <g:actionSubmit class="complete"
+                                                value="Resolved"
+                                                onclick="return confirm('${message(code:'task.clear.attention.flag.on.completion.confirm')}');"
+                                                action="complete"/>
+                    </g:if>
+                    <g:else>
+                        <g:actionSubmit class="complete" value="Resolved" action="complete"/>
+                    </g:else>
+                </span>
+                <custom:helpBalloon code="task.status.resolved" iconSrc="${resource(plugin:'help-balloons', dir:'images', file:'balloon-icon.gif')}" />
+
+
+                <g:if test="${taskInstance.approved}" >
+                    <span class="button"><g:actionSubmit class="renegeApproval" value="Renege Approval" action="renegeApproval" /></span>
+                </g:if>
+                <g:else>
+                    <span class="button"><g:actionSubmit class="approve" value="Approve" /></span>
+                </g:else>
+
+                <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                <span class="button">
+                    <g:actionSubmit class="trash"
+                                                onclick="return confirm('${message(code:'task.trash.confirm')}');"
+                                                value="Trash" />
+                </span>
+
+            </g:if>
+            <g:else>
+                <span class="button"><g:actionSubmit class="reopen" value="Reopen" /></span>
+            </g:else>
+
+        </g:else>
+    </g:form>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskModifications.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskModifications.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskModifications.gsp	(revision 875)
@@ -0,0 +1,5 @@
+    <ul>
+        <g:each var="a" in="${taskModificationList}">
+            <li>${a?.encodeAsHTML()}</li>
+        </g:each>
+    </ul>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskTab.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskTab.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/_showTaskTab.gsp	(revision 875)
@@ -0,0 +1,243 @@
+
+    <div class="dialog">
+        <table>
+            <tbody>
+
+                <g:if test="${taskInstance.parentTask}">
+                    <tr class="prop">
+                        <td valign="top" class="name">Parent Task:</td>
+
+                        <td valign="top" class="value">
+                            <g:link controller="taskDetailed" action="show" id="${taskInstance.parentTask.id}">
+                                ${taskInstance.parentTask.encodeAsHTML()}
+                            </g:link>
+                        </td>
+
+                    </tr>
+                </g:if>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Comment:</td>
+
+                    <td valign="top" class="value">${fieldValue(bean:taskInstance, field:'comment')}</td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Target Start:</td>
+
+                    <td valign="top" class="value">
+                        <g:formatDate date="${taskInstance.targetStartDate}" format="EEE, dd-MMM-yyyy"/>
+                    </td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Target Completion:</td>
+
+                    <td valign="top" class="value">
+                        <g:formatDate date="${taskInstance.targetCompletionDate}" format="EEE, dd-MMM-yyyy"/>
+                    </td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">
+
+                        <jsUtil:toggleControl toggleId="modifications"
+                                                                imageId="modificationsImg"
+                                                                closedImgUrl="${resource(dir:'images/skin',file:'bullet_toggle_plus.png')}"
+                                                                openImgUrl="${resource(dir:'images/skin',file:'bullet_toggle_minus.png')}"
+                                                                effect="fade"
+                                                                text="Modifications"
+                                                                />
+                    </td>
+
+                    <td  valign="top" style="text-align:left;" class="value">
+                        <div id="modifications" style="display:none;">
+                            <g:render template="showTaskModifications" />
+                        </div>
+                    </td>
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Primary Asset:</td>
+
+                    <td valign="top" class="value"><g:link controller="assetDetailed" action="show" id="${taskInstance?.primaryAsset?.id}">${taskInstance?.primaryAsset?.encodeAsHTML()}</g:link></td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Associated Assets:</td>
+
+                    <td  valign="top" style="text-align:left;" class="value">
+                        <ul>
+                        <g:each var="a" in="${taskInstance.associatedAssets}">
+                            <li>${a?.encodeAsHTML()}</li>
+                        </g:each>
+                        </ul>
+                    </td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Priority:</td>
+
+                    <td valign="top" class="value">${taskInstance?.taskPriority?.encodeAsHTML()}</td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Positive Fault:</td>
+
+                    <td valign="top" class="value">${fieldValue(bean:taskInstance, field:'positiveFault')}</td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Group:</td>
+
+                    <td valign="top" class="value">${taskInstance?.taskGroup?.encodeAsHTML()}</td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Type:</td>
+
+                    <td valign="top" class="value">${taskInstance?.taskType?.encodeAsHTML()}</td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Lead Person:</td>
+
+                    <td valign="top" class="value">${taskInstance?.leadPerson?.encodeAsHTML()}</td>
+
+                </tr>
+
+                <tr class="prop">
+                    <td valign="top" class="name">Assigned Groups:</td>
+
+                    <td  valign="top" style="text-align:left;" class="value">
+                        <ul>
+                        <g:each var="a" in="${assignedGroupList}">
+                            <li><g:link controller="assignedGroupDetailed" action="edit" id="${a.id}" params="['task.id':taskInstance.id]">${a?.encodeAsHTML()}</g:link></li>
+                        </g:each>
+                        </ul>
+                        <g:link controller="assignedGroupDetailed" action="create" params="['task.id':taskInstance.id]">+Add Group</g:link>
+                    </td>
+
+                </tr>
+
+
+                <tr class="prop">
+                    <td valign="top" class="name">Assigned Persons:</td>
+
+                    <td  valign="top" style="text-align:left;" class="value">
+                        <ul>
+                        <g:each var="a" in="${assignedPersonList}">
+                            <li><g:link controller="assignedPersonDetailed" action="edit" id="${a.id}" params="['task.id':taskInstance.id]">${a?.encodeAsHTML()}</g:link></li>
+                        </g:each>
+                        </ul>
+                        <g:link controller="assignedPersonDetailed" action="create" params="['task.id':taskInstance?.id]">+Add Person</g:link>
+                    </td>
+
+                </tr>
+
+            </tbody>
+        </table>
+    </div>
+
+    <div class="buttons" id="taskControlButtons">
+        <g:render template="showTaskControlButtons" />
+    </div>
+
+    <br />
+
+    <div id="entryFaultContainer">
+        <g:if test="${entryFaultList.isEmpty()}">
+            <h1>No Faults</h1>
+            <br />
+        </g:if>
+        <g:else>
+            <g:render template="/entryDetailed/list"
+                                model="['entryList':entryFaultList]" />
+        </g:else>
+    </div>
+
+    <br />
+
+    <div id="createEntryFaultContainer" style="display:none;"></div>
+
+    <div style="text-align:right;" id="entryFaultButton">
+        <span class="buttons">
+            <input type="button"
+                        class="add"
+                        value="Add Fault"
+                        onclick="getCreateEntryForm(jQuery('#entryFaultContainer'),
+                                                                            jQuery('#entryFaultButton'),
+                                                                            {target: '#createEntryFaultContainer',
+                                                                            taskId: ${taskInstance?.id},
+                                                                            entryTypeId: 1})" />
+        </span>
+    </div>
+
+    <br />
+
+    <div id="entryCauseContainer">
+        <g:if test="${entryCauseList.isEmpty()}">
+            <h1>No Causes</h1>
+            <br />
+        </g:if>
+        <g:else>
+            <g:render template="/entryDetailed/list"
+                                model="['entryList':entryCauseList]" />
+        </g:else>
+    </div>
+
+    <br />
+
+    <div id="createEntryCauseContainer" style="display:none;"></div>
+
+    <div style="text-align:right;" id="entryCauseButton">
+        <span class="buttons">
+            <input type="button"
+                        class="add"
+                        value="Add Cause"
+                        onclick="getCreateEntryForm(jQuery('#entryCauseContainer'),
+                                                                            jQuery('#entryCauseButton'),
+                                                                            {target: '#createEntryCauseContainer',
+                                                                            taskId: ${taskInstance?.id},
+                                                                            entryTypeId: 2})" />
+        </span>
+    </div>
+
+    <br />
+
+    <div id="workDoneContainer">
+        <g:if test="${entryWorkDoneList.isEmpty()}">
+            <h1>No Work Done</h1>
+            <br />
+        </g:if>
+        <g:else>
+            <g:render template="/entryDetailed/list"
+                                model="['entryList':entryWorkDoneList]" />
+        </g:else>
+    </div>
+
+    <br />
+
+    <div id="createWorkDoneContainer" style="display:none;"></div>
+
+    <div style="text-align:right;" id="workDoneButton">
+        <span class="buttons">
+            <input type="button"
+                        class="add"
+                        value="Add Work Done"
+                        onclick="getCreateEntryForm(jQuery('#workDoneContainer'),
+                                                                            jQuery('#workDoneButton'),
+                                                                            {target: '#createWorkDoneContainer',
+                                                                            taskId: ${taskInstance?.id},
+                                                                            entryTypeId: 3})" />
+        </span>
+    </div>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/create.gsp	(revision 875)
@@ -0,0 +1,200 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Task</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body onload="document.createTaskForm.description.focus();">
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${taskInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+
+            <g:form action="save" method="post" name="createTaskForm">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="primaryAsset">Asset:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'primaryAsset','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="primaryAsset.id"
+                                                        value="${taskInstance?.primaryAsset?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.none.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="task.primaryAsset" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'description','errors')}">
+                                    <input type="text"  class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:taskInstance,field:'description')}"/>
+                                    <g:helpBalloon class="helpballoon" code="task.description" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'comment','errors')}">
+                                    <textarea  rows="5" cols="40" name="comment">${fieldValue(bean:taskInstance, field:'comment')}</textarea>
+                                    <g:helpBalloon class="helpballoon" code="task.comment" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="targetStartDate">Target Start Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'targetStartDate','errors')}">
+                                    <richui:dateChooser name="targetStartDate" format="dd-MM-yyyy" value="${taskInstance.targetStartDate}" />
+                                    <g:helpBalloon class="helpballoon" code="task.targetStartDate" />
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="targetCompletionDate">Target Completion Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'targetCompletionDate','errors')}">
+                                    <richui:dateChooser name="targetCompletionDate" format="dd-MM-yyyy" value="${taskInstance.targetCompletionDate}" />
+                                    <g:helpBalloon class="helpballoon" code="task.targetCompletionDate" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="leadPerson">Lead Person:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'leadPerson','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Person.findAllByIsActive(true).sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                        name="leadPerson.id"
+                                                        value="${taskInstance?.leadPerson?.id}" >
+                                    </g:select>
+                                    <g:helpBalloon code="task.leadPerson" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="associatedAssets">Associated Assets:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'associatedAssets','errors')}">
+                                    <g:select id="associatedAssets" name="associatedAssets"
+                                                    from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                    size="5" multiple="yes" optionKey="id"
+                                                    value="${taskInstance?.associatedAssets?.id}"
+                                                    noSelection="['':/${g.message(code:'default.none.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="task.associatedAssets" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskPriority">Task Priority:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskPriority','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${scheduledTaskPriorities}"
+                                                        name="taskPriority.id"
+                                                        value="${taskInstance?.taskPriority?.id}" >
+                                    </g:select>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskGroup">Task Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${TaskGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="taskGroup.id"
+                                                        value="${taskInstance?.taskGroup?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+                                    </g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskType">Task Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskType','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${scheduledTaskTypes}"
+                                                        name="taskType.id"
+                                                        value="${taskInstance?.taskType?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+                                    </g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="safetyRequirement">Safety:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'safetyRequirement','errors')}">
+                                    <g:checkBox name="safetyRequirement" value="${taskInstance?.safetyRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.safetyRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="regulatoryRequirement">Regulatory:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'regulatoryRequirement','errors')}">
+                                    <g:checkBox name="regulatoryRequirement" value="${taskInstance?.regulatoryRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.regulatoryRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="mandatoryRequirement">Mandatory:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'mandatoryRequirement','errors')}">
+                                    <g:checkBox name="mandatoryRequirement" value="${taskInstance?.mandatoryRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.mandatoryRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="positiveFault">Positive Fault:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'positiveFault','errors')}">
+                                    <g:checkBox name="positiveFault" value="${taskInstance?.positiveFault}" ></g:checkBox>
+                                    <g:helpBalloon code="task.positiveFault" />
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/createImmediateCallout.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/createImmediateCallout.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/createImmediateCallout.gsp	(revision 875)
@@ -0,0 +1,162 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Immediate Callout</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body onload="document.createTaskForm.description.focus();">
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <g:hasErrors>
+                <div class="errors">
+                    <ul>
+                        <g:eachError bean="${taskInstance}">
+                            <li><g:message error="${it}" /></li>
+                        </g:eachError>
+                        <g:eachError bean="${entryFaultInstance}">
+                            <li><g:message error="${it}" /></li>
+                        </g:eachError>
+                        <g:eachError bean="${entryCauseInstance}">
+                            <li><g:message error="${it}" /></li>
+                        </g:eachError>
+                        <g:eachError bean="${entryWorkDoneInstance}">
+                            <li><g:message error="${it}" /></li>
+                        </g:eachError>
+                    </ul>
+                </div>
+            </g:hasErrors>
+
+            <g:form action="saveImmediateCallout" method="post" name="createTaskForm">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="primaryAsset">Asset:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'primaryAsset','errors')}">
+                                    <g:select optionKey="id"
+                                                    from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                    name="primaryAsset.id" value="${taskInstance?.primaryAsset?.id}"
+                                                    noSelection="['null':/${g.message(code:'default.none.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="task.primaryAsset" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Callout Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'description','errors')}">
+                                    <input type="text"  class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:taskInstance,field:'description')}"/>
+                                    <g:helpBalloon class="helpballoon" code="task.description.immediateCallout" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="targetStartDate">Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'targetStartDate','errors')}">
+                                    <richui:dateChooser name="targetStartDate" format="dd-MM-yyyy" value="${taskInstance.targetStartDate}" />
+                                    <g:helpBalloon class="helpballoon" code="task.targetStartDate.immediateCallout" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="productionReference">Production:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryFaultInstance,field:'productionReference','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${ProductionReference.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="entryFault.productionReference.id"
+                                                        value="${entryFaultInstance?.productionReference?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.none.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="entry.productionReference.fault" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Down Time:</label>
+                                </td>
+
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationHour','errors')}"
+                                        type="text" id="entryFault.durationHour" name="entryFault.durationHour"
+                                        value="${fieldValue(bean:entryFaultInstance,field:'durationHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationMinute','errors')}"
+                                        type="text" id="entryFault.durationMinute" name="entryFault.durationMinute" 
+                                        value="${fieldValue(bean:entryFaultInstance,field:'durationMinute')}" />
+                                    <g:helpBalloon code="entry.duration.fault" />
+                                </td> 
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">${entryFaultInstance?.entryType.encodeAsHTML()}:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryFaultInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="entryFault.comment">${fieldValue(bean:entryFaultInstance, field:'comment')}</textarea>
+                                        <g:helpBalloon code="entry.comment.fault" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">${entryCauseInstance?.entryType.encodeAsHTML()}:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryCauseInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="entryCause.comment">${fieldValue(bean:entryCauseInstance, field:'comment')}</textarea>
+                                        <g:helpBalloon code="entry.comment.cause" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">${entryWorkDoneInstance?.entryType.encodeAsHTML()}:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryWorkDoneInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="entryWorkDone.comment">${fieldValue(bean:entryWorkDoneInstance, field:'comment')}</textarea>
+                                        <g:helpBalloon code="entry.comment.work.done" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Work Duration:</label>
+                                </td>
+
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:entryWorkDoneInstance,field:'durationHour','errors')}"
+                                        type="text" id="entryWorkDone.durationHour" name="entryWorkDone.durationHour"
+                                        value="${fieldValue(bean:entryWorkDoneInstance,field:'durationHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:entryWorkDoneInstance,field:'durationMinute','errors')}"
+                                        type="text" id="entryWorkDone.durationMinute" name="entryWorkDone.durationMinute" 
+                                        value="${fieldValue(bean:entryWorkDoneInstance,field:'durationMinute')}" />
+                                    <g:helpBalloon code="entry.duration" />
+                                </td> 
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/createUnscheduled.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/createUnscheduled.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/createUnscheduled.gsp	(revision 875)
@@ -0,0 +1,172 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Task</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body onload="document.createTaskForm.description.focus();">
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+
+            <g:form action="saveUnscheduled" method="post" name="createTaskForm">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="primaryAsset">Asset:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'primaryAsset','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="primaryAsset.id"
+                                                        value="${taskInstance?.primaryAsset?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.none.select.text')}/]">
+                                        </g:select>
+                                    <g:helpBalloon code="task.primaryAsset" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'description','errors')}">
+                                    <input type="text"  class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:taskInstance,field:'description')}"/>
+                                    <g:helpBalloon class="helpballoon" code="task.description" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'comment','errors')}">
+                                    <textarea  rows="5" cols="40" name="comment">${fieldValue(bean:taskInstance, field:'comment')}</textarea>
+                                    <g:helpBalloon class="helpballoon" code="task.comment" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="targetStartDate">Target Start Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'targetStartDate','errors')}">
+                                    <richui:dateChooser name="targetStartDate" format="dd-MM-yyyy" value="${taskInstance.targetStartDate}" />
+                                    <g:helpBalloon class="helpballoon" code="task.targetStartDate" />
+                                </td>
+                            </tr> 
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="targetCompletionDate">Target Completion Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'targetCompletionDate','errors')}">
+                                    <richui:dateChooser name="targetCompletionDate" format="dd-MM-yyyy" value="${taskInstance.targetCompletionDate}" />
+                                    <g:helpBalloon class="helpballoon" code="task.targetCompletionDate" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="leadPerson">Lead Person:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'leadPerson','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Person.findAllByIsActive(true).sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                        name="leadPerson.id"
+                                                        value="${taskInstance?.leadPerson?.id}" >
+                                    </g:select>
+                                    <g:helpBalloon code="task.leadPerson" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskPriority">Task Priority:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskPriority','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${unscheduledTaskPriorities}"
+                                                        name="taskPriority.id"
+                                                        value="${taskInstance?.taskPriority?.id}" >
+                                    </g:select>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskGroup">Task Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${TaskGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="taskGroup.id"
+                                                        value="${taskInstance?.taskGroup?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+                                    </g:select>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskType">Task Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskType','errors')}">
+                                    ${taskInstance.taskType.encodeAsHTML()}
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="safetyRequirement">Safety Requirement:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'safetyRequirement','errors')}">
+                                    <g:checkBox name="safetyRequirement" value="${taskInstance?.safetyRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.safetyRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="regulatoryRequirement">Regulatory Requirement:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'regulatoryRequirement','errors')}">
+                                    <g:checkBox name="regulatoryRequirement" value="${taskInstance?.regulatoryRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.regulatoryRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="mandatoryRequirement">Mandatory Requirement:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'mandatoryRequirement','errors')}">
+                                    <g:checkBox name="mandatoryRequirement" value="${taskInstance?.mandatoryRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.mandatoryRequirement" />
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,249 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit Task #${taskInstance?.id}</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${taskInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskInstance?.id}" />
+                <input type="hidden" name="version" value="${taskInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="id">Id:</label>
+                                </td>
+                                <td valign="top" class="value">${fieldValue(bean:taskInstance, field:'id')}</td>
+                            </tr>
+
+                            <g:if test="${taskInstance?.parentTask}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">Parent Task:</td>
+
+                                    <td valign="top" class="value"><g:link controller="taskDetailed" action="show" id="${taskInstance.parentTask.id}">${taskInstance.parentTask.encodeAsHTML()}</g:link></td>
+
+                                </tr>
+                            </g:if>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'description','errors')}">
+                                    <input type="text" style="width:450px" maxlength="75" id="description" name="description" value="${fieldValue(bean:taskInstance,field:'description')}"/>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">Comment:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'comment','errors')}">
+                                    <textarea style="width:450px" rows="5" cols="40" name="comment">${fieldValue(bean:taskInstance, field:'comment')}</textarea>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="targetStartDate">Target Start Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'targetStartDate','errors')}">
+                                    <richui:dateChooser name="targetStartDate" format="dd-MM-yyyy" value="${taskInstance?.targetStartDate}" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="targetCompletionDate">Target Completion Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'targetCompletionDate','errors')}">
+                                    <richui:dateChooser name="targetCompletionDate" format="dd-MM-yyyy" value="${taskInstance?.targetCompletionDate}" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="leadPerson">Lead Person:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'leadPerson','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Person.findAllByIsActive(true).sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                        name="leadPerson.id"
+                                                        value="${taskInstance?.leadPerson?.id}" >
+                                    </g:select>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="primaryAsset">Primary Asset:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'primaryAsset','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="primaryAsset.id"
+                                                        value="${taskInstance?.primaryAsset?.id}"
+                                                        noSelection="['null':/${g.message(code:'default.none.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon code="task.primaryAsset" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="associatedAssets">Associated Assets:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'associatedAssets','errors')}">
+                                    <g:select id="associatedAssets"
+                                                    name="associatedAssets"
+                                                    from="${Asset.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                    optionKey="id" size="5" multiple="yes" 
+                                                    value="${taskInstance?.associatedAssets.id}"
+                                                    noSelection="['':/${g.message(code:'default.none.select.text')}/]">
+                                    </g:select>
+                                    <g:helpBalloon  class="helpballoon" code="task.associatedAssets" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskPriority">Task Priority:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskPriority','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${TaskPriority.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="taskPriority.id"
+                                                        value="${taskInstance?.taskPriority?.id}" >
+                                    </g:select>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskGroup">Task Group:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskGroup','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${TaskGroup.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="taskGroup.id"
+                                                        value="${taskInstance?.taskGroup?.id}" >
+                                    </g:select>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskType">Task Type:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'taskType','errors')}">
+                                    <g:select optionKey="id"
+                                                        from="${TaskType.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }}"
+                                                        name="taskType.id"
+                                                        value="${taskInstance?.taskType?.id}" >
+                                    </g:select>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="safetyRequirement">Safety Requirement:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'safetyRequirement','errors')}">
+                                    <g:checkBox name="safetyRequirement" value="${taskInstance?.safetyRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.safetyRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="regulatoryRequirement">Regulatory Requirement:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'regulatoryRequirement','errors')}">
+                                    <g:checkBox name="regulatoryRequirement" value="${taskInstance?.regulatoryRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.regulatoryRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="mandatoryRequirement">Mandatory Requirement:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'mandatoryRequirement','errors')}">
+                                    <g:checkBox name="mandatoryRequirement" value="${taskInstance?.mandatoryRequirement}" ></g:checkBox>
+                                    <g:helpBalloon code="task.mandatoryRequirement" />
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="positiveFault">Positive Fault:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'positiveFault','errors')}">
+                                    <g:checkBox name="positiveFault" value="${taskInstance?.positiveFault}" ></g:checkBox>
+                                    <g:helpBalloon code="task.positiveFault" />
+                                </td>
+                            </tr> 
+
+                            <g:if test="${taskInstance.assignedGroups}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="assignedPersons">Assigned Groups:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'assignedGroups','errors')}">
+                                        
+                                    <ul>
+                                    <g:each var="a" in="${taskInstance?.assignedGroups?}">
+                                        <li><g:link controller="assignedGroupDetailed" action="edit" id="${a.id}" params="['task.id':taskInstance?.id]">${a?.encodeAsHTML()}</g:link></li>
+                                    </g:each>
+                                    </ul>
+
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                            <g:if test="${taskInstance.assignedPersons}">
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="assignedPersons">Assigned Persons:</label>
+                                    </td>
+                                    <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'assignedPersons','errors')}">
+                                        
+                                    <ul>
+                                    <g:each var="a" in="${taskInstance?.assignedPersons?}">
+                                        <li><g:link controller="assignedPersonDetailed" action="edit" id="${a.id}" params="['task.id':taskInstance?.id]">${a?.encodeAsHTML()}</g:link></li>
+                                    </g:each>
+                                    </ul>
+
+                                    </td>
+                                </tr>
+                            </g:if>
+
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="trash" onclick="return confirm('Are you sure?');" value="Trash" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/listSubTasks.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/listSubTasks.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/listSubTasks.gsp	(revision 875)
@@ -0,0 +1,42 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Task List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+
+            <h1>Sub Tasks for:
+                <g:link action="show" id="${parentTaskInstance.id}" params="[showTab:'showSubTasksTab']">
+                    Task #${parentTaskInstance.id}
+                </g:link>
+            </h1>
+            <g:if test="${parentTaskInstance.primaryAsset}">
+                ${fieldValue(bean:parentTaskInstance, field:'primaryAsset')}:
+            </g:if>
+            ${parentTaskInstance.description}
+
+            <g:if test="${flash.message}">
+                <div class="message">${flash.message}</div>
+            </g:if>
+
+            <div class="paginateButtons">
+                Results: ${taskInstanceList.size()} / ${taskInstanceTotal}
+            </div>
+            <div class="paginateButtons">
+                <g:paginate action="listSubTasks" id="${parentTaskInstance?.id}" total="${taskInstanceTotal}" />
+            </div>
+
+            <g:render template="list" />
+
+            <div class="paginateButtons">
+                <g:paginate action="listSubTasks" id="${parentTaskInstance?.id}" total="${taskInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/search.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/search.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/search.gsp	(revision 875)
@@ -0,0 +1,119 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Task Search</title>
+        <filterpane:includes />
+        <nav:resources override="true"/>
+        <export:resource />
+        <resource:dateChooser />
+        <g:javascript src="taskQuickSearchPane.js" />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${appCore}">
+                <div class="errors">
+                    <g:renderErrors bean="${appCore}" as="list" />
+                </div>
+            </g:hasErrors>
+            <filterpane:currentCriteria domainBean="Task"
+                                    action="search"
+                                    dateFormat="EEE, dd-MMM-yyyy"
+                                    removeImgDir="images"
+                                    removeImgFile="bullet_delete.png"
+                                    title="Advanced Search"/>
+
+            <div class="paginateButtons">
+                <span class="searchButtons">
+                    <a href='' onclick="showElement('searchPane'); return false;">Quick</a>
+                </span>
+                Results: ${taskInstanceList.size()} / ${taskInstanceTotal}
+                <span class="searchButtons">
+                    <filterpane:filterButton text="Advanced" appliedText="Advanced" />
+                </span>
+            </div>
+
+            <jsUtil:toggleControl toggleId="options"
+                                                    imageId="optionsImg"
+                                                    closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                    openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                    text="${g.message(code: 'default.options.text')}"
+                                                    />
+
+            <div id="options" style="display:none;">
+                <g:form method="post" action="setSearchParamsMax" >
+                    <g:hiddenField name="params" value="${filterParams}" />
+                    <div class="dialog">
+                        <table>
+                            <tbody>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Results per page:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <input type="text" maxlength="4" id="description" name="newMax" value="${params.max}"/>
+
+                                        <span class="buttons">
+                                            <g:actionSubmit action="setSearchParamsMax" class="go" value="Update" />
+                                        </span>
+                                    </td>
+                                </tr>
+
+                            </tbody>
+                        </table>
+                    </div>
+                <export:formats  params="${filterParams}" formats="['csv', 'excel', 'pdf', 'rtf']"/>
+                </g:form>
+            </div>
+
+            <br />
+
+            <g:if test="${taskInstanceTotal > taskInstanceList.size()}">
+                <div class="paginateButtons">
+                    <g:paginate action="search" total="${taskInstanceTotal}" params="${filterParams}" />
+                </div>
+            </g:if>
+
+            <g:render template="list" />
+
+            <div class="paginateButtons">
+                <g:paginate action="search" total="${taskInstanceTotal}" params="${filterParams}" />
+            </div>
+
+            <filterpane:filterPane domainBean="Task"
+                                    title="Advanced Search"
+                                    action="search"
+                                    class="overlayPane"
+                                    additionalProperties="id"
+                                    excludeProperties="targetCompletionDate"
+                                    associatedProperties="taskPriority.name,
+                                                                                leadPerson.lastName,
+                                                                                leadPerson.firstName,
+                                                                                taskGroup.name,
+                                                                                highestSeverity.code,
+                                                                                primaryAsset.name,
+                                                                                taskStatus.name,
+                                                                                taskType.name"
+                                    filterPropertyValues="${['taskPriority.name':[values: associatedPropertyValues.taskPriorityList],
+                                                                                'leadPerson.lastName':[values: associatedPropertyValues.lastNameList],
+                                                                                'leadPerson.firstName':[values: associatedPropertyValues.firstNameList],
+                                                                                'taskGroup.name':[values: associatedPropertyValues.taskGroupList],
+                                                                                'highestSeverity.code':[values: associatedPropertyValues.highestSeverityList],
+                                                                                'primaryAsset.name':[values: associatedPropertyValues.assetList],
+                                                                                'taskStatus.name':[values: associatedPropertyValues.taskStatusList],
+                                                                                'taskType.name':[values: associatedPropertyValues.taskTypeList],
+                                                                                targetCompletionDate:[years: associatedPropertyValues.yearRange,precision:'day'],
+                                                                                targetStartDate:[years: associatedPropertyValues.yearRange,precision:'day']
+                                                                                ]}"/>
+
+            <g:render template="quickSearchPane" />
+
+        </div> <!-- end body  -->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/searchCalendar.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/searchCalendar.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/searchCalendar.gsp	(revision 875)
@@ -0,0 +1,144 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Task Search Calendar</title>
+        <filterpane:includes />
+        <nav:resources override="true"/>
+        <resource:calendarMonthView  skin="calendarmonthviewCustom"/>
+        <export:resource />
+        <resource:dateChooser />
+        <g:javascript src="taskQuickSearchPane.js" />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <filterpane:currentCriteria domainBean="Task"
+                                    action="searchCalendar"
+                                    dateFormat="EEE, dd-MMM-yyyy"
+                                    removeImgDir="images" 
+                                    removeImgFile="bullet_delete.png"
+                                    title="Advanced Search"/>
+
+
+            <div class="paginateButtons">
+                <span class="searchButtons">
+                    <a href='' onclick="showElement('searchPane'); return false;">Quick</a>
+                </span>
+                Results: ${taskInstanceList.size()} / ${taskInstanceTotal}
+                <span class="searchButtons">
+                    <filterpane:filterButton text="Advanced" appliedText="Advanced" />
+                </span>
+            </div>
+
+            <jsUtil:toggleControl toggleId="options"
+                                                    imageId="optionsImg"
+                                                    closedImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_right.png')}"
+                                                    openImgUrl="${resource(dir:'images/skin',file:'bullet_arrow_down.png')}"
+                                                    text="${g.message(code: 'default.options.text')}"
+                                                    />
+
+            <div id="options" style="display:none;">
+                <g:form method="post" action="setSearchCalendarParamsMax" >
+                    <g:hiddenField name="params" value="${filterParams}" />
+                    <div class="dialog">
+                        <table>
+                            <tbody>
+
+                                <tr class="prop">
+                                    <td valign="top" class="name">
+                                        <label for="max">Results per page:</label>
+                                    </td>
+                                    <td valign="top" class="value">
+                                        <input type="text" maxlength="4" id="description" name="newMax" value="${params.max}"/>
+
+                                        <span class="buttons">
+                                            <g:actionSubmit action="setSearchCalendarParamsMax" class="go" value="Update" />
+                                        </span>
+                                    </td>
+                                </tr>
+
+                            </tbody>
+                        </table>
+                    </div>
+                <export:formats  params="${filterParams}" formats="['csv', 'excel', 'pdf', 'rtf']"/>
+                </g:form>
+            </div>
+
+            <br />
+
+            <g:if test="${taskInstanceList.size() > 0}">
+                    <div class="paginateButtons">
+                        <g:link action="searchCalendar"
+                                        params="[showMonth: previousYear.month, showYear: previousYear.year]">
+                            &lt;&lt;
+                        </g:link>
+                        <g:link action="searchCalendar"
+                                        params="[showMonth: previousMonth.month, showYear: previousMonth.year]">
+                            &lt;
+                        </g:link>
+                        <span class="calendarMonthControlTitle">
+                            <g:formatDate date="${showDate}" format="MMMM, yyyy"/>
+                        </span>
+                        <g:link action="searchCalendar"
+                                        params="[showMonth: nextMonth.month, showYear: nextMonth.year]">
+                            &gt;
+                        </g:link>
+                        <g:link action="searchCalendar"
+                                        params="[showMonth: nextYear.month, showYear: nextYear.year]">
+                            &gt;&gt;
+                        </g:link>
+                    </div>
+                    <div>
+                        <g:link action="searchCalendar"
+                                        params="[showMonth: today.month, showYear: today.year]">
+                            Today: <g:formatDate date="${today.date}" format="MMMM, yyyy"/>
+                        </g:link>
+                    </div>
+                    <br />
+
+                <richui:calendarMonthView items="${taskInstanceList}"
+                                                                        createLink="true"
+                                                                        constraintDateFields="['targetStartDate']"
+                                                                        month="${showDate}"
+                                                                        controller="taskDetailed"
+                                                                        action="show"
+                                                                        dayAction="create"/>
+            </g:if>
+
+            <filterpane:filterPane domainBean="Task"
+                                    title="Advanced Search"
+                                    action="searchCalendar"
+                                    class="overlayPane"
+                                    additionalProperties="id"
+                                    excludeProperties="trash, targetCompletionDate"
+                                    associatedProperties="taskPriority.name,
+                                                                                leadPerson.lastName,
+                                                                                leadPerson.firstName,
+                                                                                taskGroup.name,
+                                                                                highestSeverity.code,
+                                                                                primaryAsset.name,
+                                                                                taskStatus.name,
+                                                                                taskType.name"
+                                    filterPropertyValues="${['taskPriority.name':[values: associatedPropertyValues.taskPriorityList],
+                                                                                'leadPerson.lastName':[values: associatedPropertyValues.lastNameList],
+                                                                                'leadPerson.firstName':[values: associatedPropertyValues.firstNameList],
+                                                                                'taskGroup.name':[values: associatedPropertyValues.taskGroupList],
+                                                                                'primaryAsset.name':[values: associatedPropertyValues.assetList],
+                                                                                'highestSeverity.code':[values: associatedPropertyValues.highestSeverityList],
+                                                                                'taskStatus.name':[values: associatedPropertyValues.taskStatusList],
+                                                                                'taskType.name':[values: associatedPropertyValues.taskTypeList],
+                                                                                targetCompletionDate:[years: associatedPropertyValues.yearRange,precision:'day'],
+                                                                                targetStartDate:[years: associatedPropertyValues.yearRange,precision:'day']
+                                                                                ]}"/>
+
+            <g:render template="quickSearchPane" />
+
+        </div> <!-- end body div -->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/show.gsp	(revision 875)
@@ -0,0 +1,91 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show Task #${taskInstance.id}</title>
+        <nav:resources override="true"/>
+        <resource:tabView skin="tabviewCustom" />
+        <resource:dateChooser />
+        <g:javascript src="taskShow.js" />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:if test="${taskInstance.trash}" >
+                <div class="errors">
+                        <ul><li>This task is in the trash bin, but can be restored if required.<li><ul>
+                </div>
+            </g:if>
+            <g:hasErrors bean="${taskInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+
+            <div class="tabHeader">
+                <g:render template="showTabHeader" />
+            </div>
+
+            <br/>
+
+            <richui:tabView id="tabView">
+
+                <richui:tabLabels>
+                    <richui:tabLabel selected="${showTab.task}" title="Details" />
+                    <g:if test="${taskProcedureExits}">
+                        <richui:tabLabel selected="${showTab.procedure}" title="Procedure (!)" />
+                    </g:if>
+                    <g:else>
+                        <richui:tabLabel selected="${showTab.procedure}" title="Procedure" />
+                    </g:else>
+                    <g:if test="${taskRecurringScheduleExits}">
+                        <richui:tabLabel selected="${showTab.recurrence}" title="Recurrence (!)" />
+                    </g:if>
+                    <g:else>
+                        <richui:tabLabel selected="${showTab.recurrence}" title="Recurrence" />
+                    </g:else>
+                    <g:if test="${!inventoryMovementList.isEmpty()}">
+                        <richui:tabLabel selected="${showTab.inventory}" title="Inventory (${inventoryMovementList.size()})" />
+                    </g:if>
+                    <g:else>
+                        <richui:tabLabel selected="${showTab.inventory}" title="Inventory (0)" />
+                    </g:else>
+                    <g:if test="${subTaskInstanceTotal > 0}">
+                        <richui:tabLabel selected="${showTab.subTasks}" title="Sub Tasks (${subTaskInstanceTotal})" />
+                    </g:if>
+                    <g:else>
+                        <richui:tabLabel selected="${showTab.subTasks}" title="Sub Tasks (0)" />
+                    </g:else>
+                </richui:tabLabels>
+
+                <richui:tabContents>
+
+                    <richui:tabContent>
+                        <g:render template="showTaskTab" />
+                    </richui:tabContent>
+
+                    <richui:tabContent>
+                        <g:render template="showProcedureTab" />
+                    </richui:tabContent>
+
+                    <richui:tabContent>
+                        <g:render template="showRecurrenceTab" />
+                    </richui:tabContent>
+
+                    <richui:tabContent>
+                        <g:render template="showInventoryTab" />
+                    </richui:tabContent>
+
+                    <richui:tabContent>
+                        <g:render template="showSubTaskTab" />
+                    </richui:tabContent>
+
+                </richui:tabContents>
+            </richui:tabView>
+
+        </div> <!--body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/workDone.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/workDone.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/workDone.gsp	(revision 875)
@@ -0,0 +1,114 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Work Done</title>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Work Done</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <div class="paginateButtons">
+                Results: ${totalEntries}
+                <span class="searchButtons">
+                    <a href='' onclick="showElement('searchPane'); return false;">Search</a>
+                </span>
+            </div>
+
+            <br />
+
+                <g:if test="${entries.size() > 0}">
+                            <div class="list">
+                                <table>
+                                    <thead>
+                                        <tr>
+                                            <th>Task</th>
+                                            <th>Work Done</th>
+                                            <th>Duration</th>
+                                            <th></th>
+                                        </tr>
+                                    </thead>
+                                    <tbody>
+                                        <g:each in="${entries}" status="i" var="entry">
+                                                <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                                                    <td width="35%" onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                                        ${entry.task.encodeAsHTML()}
+                                                    </td>
+                                                    <td width="60%" onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                                        ${entry.comment.encodeAsHTML()}
+                                                    </td>
+                                                    <td onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'>
+                                                        ${entry.durationHour}:<g:formatNumber number="${entry.durationMinute}" type="number" minIntegerDigits="2" />
+                                                    </td>
+
+                                                    <td class="notClickable">
+                                                        <g:link controller="entryDetailed" action="edit" id="${entry.id}">
+                                                            <img  src="${resource(dir:'images/skin',file:'database_edit.png')}" alt="Edit" />
+                                                        </g:link>
+                                                    </td>
+
+                                                </tr>
+                                        </g:each>
+                                        <tr class="total">
+                                            <td>
+                                                Total
+                                            </td>
+                                            <td>
+                                            </td>
+                                            <td>
+                                                ${totalHours}:<g:formatNumber number="${totalMinutes}" type="number" minIntegerDigits="2" />
+                                            </td>
+                                            <td>
+                                            </td>
+                                        </tr>
+                                    </tbody>
+                                </table>
+                            </div>
+                        </g:if>
+
+            <!-- Start Search Pane -->
+            <div class="overlayPane" id="searchPane" style="display:none;">
+                <h2>Search</h2>
+                <g:form method="post" controller="taskDetailed">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">Person:</td>
+                                <td valign="top" class="value">
+                                    <g:select optionKey="id"
+                                                        from="${Person.findAllByIsActive(true).sort { p1, p2 -> p1.firstName.compareToIgnoreCase(p2.firstName) }}"
+                                                        name="person.id"
+                                                        value="${person.id}" >
+                                    </g:select>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="date">Date:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <richui:dateChooser name="date" format="dd-MM-yyyy" value="${startOfDay}" />
+                                </td>
+                            </tr>
+
+                        </tbody>
+                    </table>
+                    <div class="buttons">
+                        <span class="button">
+                            <g:actionSubmit class="save" value="Update" action="workDone" />
+                            <g:actionSubmit class="cancel" value="${g.message(code:'fp.tag.filterPane.button.cancel.text', default:'Cancel')}" onclick="return hideElement('searchPane');" />
+                        </span>
+                    </div>
+                </g:form>
+            </div> <!-- end search pane -->
+
+        </div> <!--body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskDetailed/workLoad.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskDetailed/workLoad.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskDetailed/workLoad.gsp	(revision 875)
@@ -0,0 +1,133 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Work Load</title>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Work Load</h1>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <div class="paginateButtons">
+                <span class="searchButtons">
+                    <a href='' onclick="showElement('searchPane'); return false;">Search</a>
+                </span>
+            </div>
+
+            <br />
+
+
+            <g:if test="${workLoadGroups.size() > 0}">
+                <h1>Assigned Groups</h1>
+            </g:if>
+            <g:else>
+                <h1>No Assigned Groups Found</h1>
+            </g:else>
+                    <div class="list">
+                        <table>
+                            <thead>
+                                <tr>
+                                    <th>Assigned Group</th>
+                                    <th>Duration</th>
+                                </tr>
+                            </thead>
+                            <tbody>
+                                <g:each in="${workLoadGroups}" status="i" var="workLoadGroup">
+                                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                                            <td class="notClickable">
+                                                ${workLoadGroup.key}
+                                            </td>
+
+                                            <td class="notClickable">
+                                                ${workLoadGroup.value.hours}:<g:formatNumber number="${workLoadGroup.value.minutes}" type="number" minIntegerDigits="2" />
+                                            </td>
+
+                                        </tr>
+                                </g:each>
+                                <tr class="total">
+                                    <td>
+                                        Total
+                                    </td>
+                                    <td>
+                                        ${totalHours}:<g:formatNumber number="${totalMinutes}" type="number" minIntegerDigits="2" />
+                                    </td>
+                                </tr>
+                            </tbody>
+                        </table>
+                    </div>
+
+            <br />
+
+            <h1>Task Results: ${tasks.size()} / ${tasks.totalCount}</h1>
+
+            <g:render template="list" model="[taskInstanceList:tasks]"/>
+
+            <!-- Start Search Pane -->
+            <div class="overlayPane" id="searchPane" style="display:none;">
+                <h2>Search</h2>
+                <g:form method="post" controller="taskDetailed">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="date">Date:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <richui:dateChooser name="startDate" format="dd-MM-yyyy" value="${startDate}" />
+                                    to
+                                    <richui:dateChooser name="endDate" format="dd-MM-yyyy" value="${endDate}" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Task Status:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:checkBoxList name="taskStatusList"
+                                                                            from="${TaskStatus.findAllByIsActive(true)}"
+                                                                            value="${taskStatusList?.collect{it.id}}"
+                                                                            optionKey="id"
+                                                                            sortBy="name"
+                                                                            linkController="taskStatusDetailed"
+                                                                            linkAction="show"
+                                                                            height="150px"/>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label>Task Groups:</label>
+                                </td>
+                                <td valign="top" class="value">
+                                    <custom:checkBoxList name="taskGroups"
+                                                                            from="${TaskGroup.findAllByIsActive(true)}"
+                                                                            value="${taskGroups?.collect{it.id}}"
+                                                                            optionKey="id"
+                                                                            sortBy="name"
+                                                                            linkController="taskGroupDetailed"
+                                                                            linkAction="show"
+                                                                            height="150px"/>
+                                </td>
+                            </tr>
+
+                        </tbody>
+                    </table>
+                    <div class="buttons">
+                        <span class="button">
+                            <g:actionSubmit class="save" value="Update" action="workLoad" />
+                            <g:actionSubmit class="cancel" value="${g.message(code:'fp.tag.filterPane.button.cancel.text', default:'Cancel')}" onclick="return hideElement('searchPane');" />
+                        </span>
+                    </div>
+                </g:form>
+            </div> <!-- end search pane -->
+
+        </div> <!--body-->
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/create.gsp	(revision 875)
@@ -0,0 +1,62 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${taskGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,66 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${taskGroupInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskGroupInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskGroupInstance?.id}" />
+                <input type="hidden" name="version" value="${taskGroupInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskGroupInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskGroupInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskGroupInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskGroupInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskGroupInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskGroupInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/list.gsp	(revision 875)
@@ -0,0 +1,69 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskGroup List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${taskGroupInstanceList}" status="i" var="taskGroupInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskGroupDetailed/show/${taskGroupInstance.id}"'>
+                                    ${fieldValue(bean:taskGroupInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskGroupDetailed/show/${taskGroupInstance.id}"'>
+                                ${fieldValue(bean:taskGroupInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskGroupDetailed/show/${taskGroupInstance.id}"'>
+                                ${fieldValue(bean:taskGroupInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskGroupDetailed/show/${taskGroupInstance.id}"'>
+                                ${fieldValue(bean:taskGroupInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${taskGroupInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${taskGroupInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskGroupDetailed/show.gsp	(revision 875)
@@ -0,0 +1,61 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskGroup</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskGroupInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskGroupInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskGroupInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskGroupInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${taskGroupInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskModificationType/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskModificationType/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskModificationType/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskModificationType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskModificationType List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create TaskModificationType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskModificationTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskModificationTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskModificationTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskModificationTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskModificationTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskModificationTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskModificationTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskModificationTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskModificationType/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskModificationType/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskModificationType/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskModificationType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskModificationType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskModificationType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit TaskModificationType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskModificationTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskModificationTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskModificationTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${taskModificationTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskModificationTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskModificationTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskModificationTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskModificationTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskModificationTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskModificationTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskModifications">Task Modifications:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskModificationTypeInstance,field:'taskModifications','errors')}">
+                                    
+<ul>
+<g:each var="t" in="${taskModificationTypeInstance?.taskModifications?}">
+    <li><g:link controller="taskModification" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="taskModification" params="['taskModificationType.id':taskModificationTypeInstance?.id]" action="create">Add TaskModification</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskModificationType/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskModificationType/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskModificationType/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskModificationType List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New TaskModificationType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>TaskModificationType List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${taskModificationTypeInstanceList}" status="i" var="taskModificationTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${taskModificationTypeInstance.id}">${fieldValue(bean:taskModificationTypeInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:taskModificationTypeInstance, field:'name')}</td>
+                        
+                            <td>${fieldValue(bean:taskModificationTypeInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:taskModificationTypeInstance, field:'isActive')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${taskModificationTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskModificationType/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskModificationType/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskModificationType/show.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskModificationType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskModificationType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskModificationType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show TaskModificationType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskModificationTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskModificationTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskModificationTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskModificationTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Task Modifications:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="t" in="${taskModificationTypeInstance.taskModifications}">
+                                    <li><g:link controller="taskModification" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${taskModificationTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskPriority/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskPriority/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskPriority/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskPriority</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskPriority List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create TaskPriority</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskPriorityInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskPriorityInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskPriorityInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskPriorityInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskPriorityInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskPriorityInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskPriorityInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskPriorityInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskPriority/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskPriority/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskPriority/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskPriority</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskPriority List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskPriority</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit TaskPriority</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskPriorityInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskPriorityInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskPriorityInstance?.id}" />
+                <input type="hidden" name="version" value="${taskPriorityInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskPriorityInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskPriorityInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskPriorityInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskPriorityInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskPriorityInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskPriorityInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="tasks">Tasks:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskPriorityInstance,field:'tasks','errors')}">
+                                    
+<ul>
+<g:each var="t" in="${taskPriorityInstance?.tasks?}">
+    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="task" params="['taskPriority.id':taskPriorityInstance?.id]" action="create">Add Task</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskPriority/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskPriority/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskPriority/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskPriority List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New TaskPriority</g:link></span>
+        </div>
+        <div class="body">
+            <h1>TaskPriority List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${taskPriorityInstanceList}" status="i" var="taskPriorityInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${taskPriorityInstance.id}">${fieldValue(bean:taskPriorityInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:taskPriorityInstance, field:'name')}</td>
+                        
+                            <td>${fieldValue(bean:taskPriorityInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:taskPriorityInstance, field:'isActive')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${taskPriorityInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskPriority/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskPriority/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskPriority/show.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskPriority</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskPriority List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskPriority</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show TaskPriority</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskPriorityInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskPriorityInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskPriorityInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskPriorityInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Tasks:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="t" in="${taskPriorityInstance.tasks}">
+                                    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${taskPriorityInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_documentReference.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_documentReference.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_documentReference.gsp	(revision 875)
@@ -0,0 +1,23 @@
+
+    <tr id="documentReferenceLazyList${i}" class="docRef-div" <g:if test="${docRef?.toBeDeleted}">style="display:none;"</g:if>>
+
+        <td valign="top" class="${hasErrors(bean:docRef,field:'name','errors')}">
+            <g:hiddenField name="documentReferenceLazyList[${i}].toBeDeleted" value="${docRef?.toBeDeleted}"/>
+            <g:hiddenField name='documentReferenceLazyList[${i}].isNew' value="${docRef?.id == null?'true':'false'}"/>
+            <g:textArea name="documentReferenceLazyList[${i}].name"
+                                    value="${docRef?.name}"
+                                    style="width:420px;height:auto;"/>
+        </td>
+
+        <td valign="top" class="${hasErrors(bean:docRef,field:'location','errors')}">
+            <g:textArea name="documentReferenceLazyList[${i}].location"
+                                    value="${docRef?.location}"
+                                    style="width:420px;height:auto;"/>
+        </td>
+
+        <td>
+            <span class="del-docRef">
+                <img src="${resource(dir:'images/skin', file:'database_delete.png')}" />
+            </span>
+        </td>
+    </tr>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_documentReferences.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_documentReferences.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_documentReferences.gsp	(revision 875)
@@ -0,0 +1,62 @@
+<script type="text/javascript">
+    var docRef_childCount = ${taskProcedureInstance?.documentReferences.size()} + 0;
+    var docRef_wrapperId = "docRef_wrapper";
+    var docRef_cloneId = "documentReferenceLazyList_clone";
+    var docRef_lazyList = "documentReferenceLazyList";
+    var docRef_fields = ["toBeDeleted", "isNew", "name", "location"];
+    var docRef_focusField = "name";
+
+    // Click event on add button.
+    jQuery('.add-docRef').live('click', function() {
+        addChild(docRef_wrapperId, docRef_cloneId, docRef_lazyList, docRef_fields, docRef_focusField, docRef_childCount);
+        docRef_childCount++;
+    });
+
+    // Click event on delete buttons.
+    jQuery('.del-docRef').live('click', function() {
+        //find the parent div
+        var prnt = jQuery(this).parents(".docRef-div");
+        //find the deleted hidden input
+        var delInput = prnt.find("input[id$=toBeDeleted]");
+        //check if this is still not persisted
+        var newValue = prnt.find("input[id$=isNew]").attr('value');
+        //if it is new then i can safely remove from dom
+        if(newValue == 'true'){
+            prnt.remove();
+        }else{
+            //set the deletedFlag to true
+            delInput.attr('value','true');
+            //hide the div
+            prnt.hide();
+        }
+    });
+
+</script>
+
+    <div>
+        <table>
+            <thead>
+                <tr>
+
+                    <th>Document Reference Name</th>
+                    <th>Location</th>
+                    <th></th>
+
+                </tr>
+            </thead>
+            <tbody id="docRef_wrapper">
+                <g:each var="docRef" in="${taskProcedureInstance.documentReferences}" status="i">
+                        <g:render template="documentReference" model="['docRef': docRef,
+                                                                                                                    'i':i]" />
+                </g:each>
+            </tbody>
+        </table>
+    </div>
+
+    <br />
+
+    <div style="text-align:right;">
+        <span class="buttons add-docRef">
+            <input type="button" class="add" value="Add Document Ref" />
+        </span>
+    </div>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_maintenanceAction.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_maintenanceAction.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_maintenanceAction.gsp	(revision 875)
@@ -0,0 +1,38 @@
+
+    <tr id="maintenanceActionLazyList${i}" class="ma-div" <g:if test="${ma?.toBeDeleted}">style="display:none;"</g:if>>
+
+        <td valign="top" class="${hasErrors(bean:ma,field:procedureStepNumber,'errors')}">
+            <g:hiddenField name="maintenanceActionLazyList[${i}].toBeDeleted" value="${ma?.toBeDeleted}"/>
+            <g:hiddenField name='maintenanceActionLazyList[${i}].isNew' value="${ma?.id == null?'true':'false'}"/>
+            <g:textField name="maintenanceActionLazyList[${i}].procedureStepNumber"
+                                    value="${ma?.procedureStepNumber}"
+                                    style="width:3em;"/>
+        </td>
+
+        <td valign="top" class="${hasErrors(bean:ma,field:'assetSubItem','errors')}">
+            <g:select optionKey="id"
+                                from="${assemblies}"
+                                name="maintenanceActionLazyList[${i}].assetSubItem.id"
+                                value="${ma?.assetSubItem?.id}"
+                                noSelection="['null':/${g.message(code:'default.please.select.text')}/]">
+            </g:select>
+        </td>
+
+        <td valign="top" class="${hasErrors(bean:ma,field:'description','errors')}">
+            <g:textArea name="maintenanceActionLazyList[${i}].description"
+                                    value="${ma?.description}"
+                                    style="width:280px;height:auto;"/>
+        </td>
+
+        <td valign="top" class="${hasErrors(bean:ma,field:'pageRef','errors')}">
+            <g:textArea name="maintenanceActionLazyList[${i}].pageRef"
+                                    value="${ma?.pageRef}"
+                                    style="width:100px;height:auto;"/>
+        </td>
+
+        <td>
+            <span class="del-ma">
+                <img src="${resource(dir:'images/skin', file:'database_delete.png')}" />
+            </span>
+        </td>
+    </tr>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_maintenanceActions.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_maintenanceActions.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_maintenanceActions.gsp	(revision 875)
@@ -0,0 +1,75 @@
+<script type="text/javascript">
+    var ma_childCount = ${taskProcedureInstance?.maintenanceActions.size()} + 0;
+    var ma_wrapperId = "ma_wrapper";
+    var ma_cloneId = "maintenanceActionLazyList_clone";
+    var ma_lazyList = "maintenanceActionLazyList";
+    var ma_fields = ["toBeDeleted", "isNew", "description", "pageRef", "assetSubItem.id", "procedureStepNumber"];
+    var ma_focusField = "procedureStepNumber";
+
+    // Click event on add button.
+    jQuery('.add-ma').live('click', function() {
+        addChild(ma_wrapperId, ma_cloneId, ma_lazyList, ma_fields, ma_focusField, ma_childCount);
+        ma_childCount++;
+    });
+
+    // Click event on delete buttons.
+    jQuery('.del-ma').live('click', function() {
+        //find the parent div
+        var prnt = jQuery(this).parents(".ma-div");
+        //find the deleted hidden input
+        var delInput = prnt.find("input[id$=toBeDeleted]");
+        //check if this is still not persisted
+        var newValue = prnt.find("input[id$=isNew]").attr('value');
+        //if it is new then i can safely remove from dom
+        if(newValue == 'true'){
+            prnt.remove();
+        }else{
+            //set the deletedFlag to true
+            delInput.attr('value','true');
+            //hide the div
+            prnt.hide();
+        }
+    });
+
+    jQuery(window).load(function() {
+        if(ma_childCount == 0) {
+            addChild(ma_wrapperId, ma_cloneId, ma_lazyList, ma_fields, ma_focusField, ma_childCount);
+            ma_childCount++;
+        }
+    });
+
+</script>
+
+
+
+    <div>
+        <table>
+            <thead>
+                <tr>
+
+                    <th>Step</th>
+                    <th>Assembly</th>
+                    <th>Description</th>
+                    <th>Page Ref</th>
+                    <th></th>
+
+                </tr>
+            </thead>
+            <tbody id="ma_wrapper">
+                <g:each var="ma" in="${taskProcedureInstance.maintenanceActions}" status="i">
+                        <g:render template="maintenanceAction" model="['tp':taskProcedureInstance,
+                                                                                                            'ma': ma,
+                                                                                                            'i':i,
+                                                                                                            'assemblies': assemblies]" />
+                </g:each>
+            </tbody>
+        </table>
+    </div>
+
+    <br />
+
+    <div style="text-align:right;">
+        <span class="buttons add-ma">
+            <input type="button" class="add" value="Add MaintenanceAction" />
+        </span>
+    </div>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_taskProcedure.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_taskProcedure.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_taskProcedure.gsp	(revision 875)
@@ -0,0 +1,60 @@
+
+<div class="dialog">
+    <table>
+        <tbody>
+
+            <g:if test="${taskProcedureInstance.id}">
+                <tr class="prop">
+                    <td valign="top" class="name">Procedure Id:</td>
+                    <td valign="top" class="value">
+                        ${fieldValue(bean:taskProcedureInstance, field:'id')}
+                    </td>
+                </tr>
+            </g:if>
+
+            <tr class="prop">
+                <td valign="top" class="name">
+                    <label for="taskInstance">Linked Task:</label>
+                </td>
+                <td valign="top" name="taskInstance" class="value">
+                    <g:link controller="taskDetailed" action="show" id="${taskProcedureInstance.linkedTask.id}">
+                        ${taskProcedureInstance.linkedTask.encodeAsHTML()}
+                    </g:link>
+                </td>
+            </tr>
+
+            <tr class="prop">
+                <td valign="top" class="name">Linked Asset:</td>
+                <td valign="top" class="value">
+                    <g:render template="/shared/assetTreeCompact" model="['assetInstance': taskProcedureInstance.linkedTask.primaryAsset]" />
+                </td>
+            </tr>
+
+            <g:if test="${taskProcedureInstance.id}">
+                <tr class="prop">
+                    <td valign="top" class="name">Revisions:</td>
+                    <td valign="top" class="value">
+                        <ul>
+                        <g:each var="r" in="${taskProcedureInstance.revisions}">
+                            <li>
+                                <g:link action="show" id="${taskProcedureInstance.id}" params="['revision':r.revision]">
+                                    ${r.fullRevisionString.encodeAsHTML()}
+                                </g:link>
+                            </li>
+                        </g:each>
+                        </ul>
+                    </td>
+                </tr>
+            </g:if>
+
+        </tbody>
+    </table>
+
+    <br />
+    <g:render template="documentReferences" model="['taskProcedureInstance': taskProcedureInstance]" />
+
+    <br />
+    <g:render template="maintenanceActions" model="['taskProcedureInstance': taskProcedureInstance,
+                                                                                        'assemblies': assemblies]" />
+    <br />
+</div>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_taskProcedureRevision.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_taskProcedureRevision.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/_taskProcedureRevision.gsp	(revision 875)
@@ -0,0 +1,140 @@
+
+        <div class="dialog">
+            <table>
+                <tbody>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Procedure Id:</td>
+                        <td valign="top" class="value">
+                            ${fieldValue(bean:taskProcedureRevision, field:'taskProcedureId')}
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Linked Task:</td>
+                        <td valign="top" class="value">
+                            <g:link controller="taskDetailed"
+                                            action="show"
+                                            id="${taskProcedureRevision.linkedTask.id}">
+                                ${taskProcedureRevision.linkedTask.encodeAsHTML()}
+                            </g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Linked Asset:</td>
+                        <td valign="top" class="value">
+                            <g:render template="/shared/assetTreeCompact" model="['assetInstance': taskProcedureRevision.linkedTask.primaryAsset]" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Revision:</td>
+                        <td valign="top" class="value">
+                            ${fieldValue(bean:taskProcedureRevision, field:'revisionDateString')}
+                        </td>
+                    </tr>
+
+                </tbody>
+            </table>
+        </div>
+        <div class="buttons">
+            <g:form controller="taskProcedureDetailed">
+                <input type="hidden" name="id" value="${taskProcedureRevision.taskProcedureId}" />
+                Latest Revision: ${taskProcedureRevision?.taskProcedure.revision}
+                <span class="button">
+                    <g:actionSubmit class="edit" value="Edit" />
+                </span>
+                <span class="button">
+                    <g:actionSubmit class="go" value="Show" />
+                </span>
+            </g:form>
+        </div>
+
+        <br />
+
+        <g:if test="${taskProcedureRevision.documentReferences}">
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                            <th>Document Reference</th>
+                            <th>Location</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        <g:each in="${taskProcedureRevision.documentReferences}" status="i" var="docRef">
+                            <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+
+                                <td valign="top" class="name">
+                                    ${fieldValue(bean:docRef, field:'name')}
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <custom:easyUrl url="${docRef.location}" />
+                                </td>
+
+                            </tr>
+                        </g:each>
+
+                    </tbody>
+                </table>
+            </div>
+        </g:if>
+
+        <br />
+
+        <g:if test="${taskProcedureRevision.maintenanceActions}">
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                            <th>Step</th>
+                            <th>Assembly</th>
+                            <th>Description</th>
+                            <th>Page Ref</th>
+                            <th>Condition</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        <g:each in="${taskProcedureRevision.maintenanceActions}" status="i" var="maintenanceAction">
+                            <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+
+                                <td valign="top" class="name">
+                                    ${fieldValue(bean:maintenanceAction, field:'procedureStepNumber')}
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <g:if test="${maintenanceAction.assetSubItem}">
+                                        ${maintenanceAction.assetSubItem.parentItem?.encodeAsHTML()}
+                                        --
+                                        ${maintenanceAction.assetSubItem.encodeAsHTML()}
+                                    </g:if>
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    ${fieldValue(bean:maintenanceAction, field:'description')}
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    ${maintenanceAction.pageRef.encodeAsHTML() ?: '-'}
+                                </td>
+
+                                <td  valign="top" style="text-align:left; white-space:nowrap;" class="value">
+                                    ${'A | B | C | D | E'}
+                                </td>
+
+                            </tr>
+                        </g:each>
+
+                    </tbody>
+                </table>
+                <div class="buttons">
+                    <g:set var="conditionSeverityList" value="${ConditionSeverity.findAllByIsActive(true)}" />
+
+                    <% out << conditionSeverityList[0..1].join(' | ') %>
+                    <br />
+                    <% out << conditionSeverityList[2..-1].join(' | ') %>
+                </div>
+            </div>
+        </g:if>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/create.gsp	(revision 875)
@@ -0,0 +1,45 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskProcedure</title>
+        <nav:resources override="true"/>
+        <g:javascript src="dynamicOneToMany.js" />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <g:hasErrors bean="${taskProcedureInstance}">
+                <div class="errors">
+                    <g:renderErrors bean="${taskProcedureInstance}" as="list" />
+                </div>
+            </g:hasErrors>
+
+            <g:form action="save" method="post" >
+                <input type="hidden" name="linkedTask.id" value="${taskProcedureInstance.linkedTask.id}" />
+
+                <g:render template="taskProcedure" model="['taskProcedureInstance': taskProcedureInstance]" />
+
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+        <table style="display:none;">
+            <g:render template="documentReference" model="['docRef': null,
+                                                                                                        'i': '_clone']" />
+        </table>
+        <table style="display:none;">
+            <g:render template="maintenanceAction" model="['tp': null,
+                                                                                                'ma': null,
+                                                                                                'i': '_clone',
+                                                                                                'assemblies': assemblies]" />
+        </table>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,47 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskProcedure</title>
+        <nav:resources override="true"/>
+        <g:javascript src="dynamicOneToMany.js" />
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+
+            <g:hasErrors bean="${taskProcedureInstance}">
+                <div class="errors">
+                    <g:renderErrors bean="${taskProcedureInstance}" as="list" />
+                </div>
+            </g:hasErrors>
+
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskProcedureInstance?.id}" />
+                <input type="hidden" name="version" value="${taskProcedureInstance?.version}" />
+
+                <g:render template="taskProcedure" model="['taskProcedureInstance': taskProcedureInstance]" />
+
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                </div>
+            </g:form>
+        </div>
+        <table style="display:none;">
+            <g:render template="documentReference" model="['docRef': null,
+                                                                                                        'i': '_clone']" />
+        </table>
+        <table style="display:none;">
+            <g:render template="maintenanceAction" model="['tp': null,
+                                                                                                'ma': null,
+                                                                                                'i': '_clone',
+                                                                                                'assemblies': assemblies]" />
+        </table>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/list.gsp	(revision 875)
@@ -0,0 +1,82 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskProcedure List</title>
+        <filterpane:includes />
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <filterpane:currentCriteria domainBean="TaskProcedure"
+                                    action="list"
+                                    dateFormat="EEE, dd-MMM-yyyy"
+                                    removeImgDir="images" 
+                                    removeImgFile="bullet_delete.png"
+                                    title="Search"/>
+
+            <div class="paginateButtons">
+                <span class="searchButtons">
+                    <filterpane:filterButton text="Search" appliedText="Change Search" />
+                </span>
+                Results: ${taskProcedureInstanceList.size()} / ${taskProcedureInstanceTotal}
+            </div>
+
+
+            <g:if test="${taskProcedureInstanceList.size() > 0}">
+                <div class="list">
+                    <table>
+                        <thead>
+                            <tr>
+
+                                <g:sortableColumn property="id" title="Id"  params="${filterParams}" />
+                                <th>Description</th>
+                                <th>Asset</th>
+
+                                <th></th>
+
+                            </tr>
+                        </thead>
+                        <tbody>
+                        <g:each in="${taskProcedureInstanceList}" status="i" var="taskProcedureInstance">
+                            <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}" onclick='window.location = "${request.getContextPath()}/taskProcedureDetailed/show/${taskProcedureInstance.id}"'/>
+
+                                <td>${fieldValue(bean:taskProcedureInstance, field:'id')}</td>
+
+                                <td>${taskProcedureInstance.description.encodeAsHTML()}</td>
+
+                                <td>${taskProcedureInstance.asset?.encodeAsHTML()}</td>
+
+                                <td>
+                                    <g:link action="show" id="${taskProcedureInstance.id}">
+                                        <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                    </g:link>
+                                </td>
+
+                            </tr>
+                        </g:each>
+                        </tbody>
+                    </table>
+                </div>
+            </g:if>
+
+            <div class="paginateButtons">
+                <g:paginate total="${taskProcedureInstanceTotal}" params="${filterParams}" />
+            </div>
+
+            <filterpane:filterPane domainBean="TaskProcedure"
+                                    title="Search"
+                                    action="list"
+                                    class="overlayPane"
+                                    additionalProperties="id"
+                                    excludeProperties=""
+                                    associatedProperties="linkedTask.description" />
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskProcedureDetailed/show.gsp	(revision 875)
@@ -0,0 +1,23 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskProcedure</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+
+
+            <g:render template="/taskProcedureDetailed/taskProcedureRevision" />
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/create.gsp	(revision 875)
@@ -0,0 +1,128 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskRecurringSchedule</title>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Create Recurring Schedule</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskRecurringScheduleInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskRecurringScheduleInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <g:hiddenField name="task.id" value="${taskRecurringScheduleInstance.task.id}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="recForTask">Recurring Schedule for Task:</label>
+                                </td>
+                                <td valign="top" name="recForTask" class="value">
+                                    <g:link controller="taskDetailed" action="show" id="${taskRecurringScheduleInstance?.task?.id}">${taskRecurringScheduleInstance?.task?.encodeAsHTML()}</g:link>
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="nextTargetStartDate">Next Target Start Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'nextTargetStartDate','errors')}">
+                                    <richui:dateChooser name="nextTargetStartDate" format="dd-MM-yyyy" value="${taskRecurringScheduleInstance?.nextTargetStartDate}" />
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.nextTargetStartDate" />
+                                </td>
+                            </tr>   
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="recurEvery">Recur Every:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'recurEvery','errors')}"
+                                        id="recurEvery" name="recurEvery" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'recurEvery')}" />
+                                    <g:select optionKey="id" from="${Period.list()}" name="recurPeriod.id" value="${taskRecurringScheduleInstance?.recurPeriod?.id}" ></g:select>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.recurEvery" />
+                                </td>
+                            </tr>   
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskDuration">Task Duration:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'taskDuration','errors')}"
+                                        id="taskDuration" name="taskDuration" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'taskDuration')}" />
+                                    <g:select optionKey="id" from="${Period.list()}" name="taskDurationPeriod.id" value="${taskRecurringScheduleInstance?.taskDurationPeriod?.id}" ></g:select>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.taskDuration" />
+                                </td>
+                            </tr>   
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="generateAhead">Generate Ahead:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'generateAhead','errors')}"
+                                        id="generateAhead" name="generateAhead" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'generateAhead')}" />
+                                        ${Period.get(1).encodeAsHTML()}
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.generateAhead" />
+                                </td>
+                            </tr>
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="maxSubTasks">Max Sub Tasks:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'maxSubTasks','errors')}"
+                                        id="maxSubTasks" name="maxSubTasks" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'maxSubTasks')}" />
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.maxSubTasks" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="useTargetCompletionDate">Use Target Completion Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'useTargetCompletionDate','errors')}">
+                                    <g:checkBox name="useTargetCompletionDate"
+                                                            value="${taskRecurringScheduleInstance?.useTargetCompletionDate}" >
+                                    </g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.useTargetCompletionDate" />
+                                    <g:formatDate date="${taskRecurringScheduleInstance.task.targetCompletionDate}"
+                                                                    format="EEE, dd-MMM-yyyy"/>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="enabled">Enabled:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'enabled','errors')}">
+                                    <g:checkBox name="enabled" value="${taskRecurringScheduleInstance?.enabled}" ></g:checkBox>
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.enabled" />
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,130 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskRecurringSchedule</title>
+        <resource:dateChooser />
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Edit Recurring Schedule</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskRecurringScheduleInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskRecurringScheduleInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskRecurringScheduleInstance?.id}" />
+                <input type="hidden" name="version" value="${taskRecurringScheduleInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="recForTask">Recurring Schedule for Task:</label>
+                                </td>
+                                <td valign="top" name="recForTask" class="value">
+                                    <g:link controller="taskDetailed" action="show" id="${taskRecurringScheduleInstance?.task?.id}">${taskRecurringScheduleInstance?.task?.encodeAsHTML()}</g:link>
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="enabled">Enabled:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'enabled','errors')}">
+                                    <g:checkBox name="enabled" value="${taskRecurringScheduleInstance?.enabled}" ></g:checkBox>
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.enabled" />
+                                </td>
+                            </tr>
+                            
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="nextTargetStartDate">Next Target Start Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'nextTargetStartDate','errors')}">
+                                    <richui:dateChooser name="nextTargetStartDate" format="dd-MM-yyyy" value="${taskRecurringScheduleInstance?.nextTargetStartDate}" />
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.nextTargetStartDate" />
+                                </td>
+                            </tr>   
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="recurEvery">Recur Every:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'recurEvery','errors')}"
+                                        id="recurEvery" name="recurEvery" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'recurEvery')}" />
+                                    <g:select optionKey="id" from="${Period.list()}" name="recurPeriod.id" value="${taskRecurringScheduleInstance?.recurPeriod?.id}" ></g:select>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.recurEvery" />
+                                </td>
+                            </tr>   
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="taskDuration">Task Duration:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'taskDuration','errors')}"
+                                        id="taskDuration" name="taskDuration" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'taskDuration')}" />
+                                    <g:select optionKey="id" from="${Period.list()}" name="taskDurationPeriod.id" value="${taskRecurringScheduleInstance?.taskDurationPeriod?.id}" ></g:select>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.taskDuration" />
+                                </td>
+                            </tr>       
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="generateAhead">Generate Ahead:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'generateAhead','errors')}"
+                                        id="generateAhead" name="generateAhead" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'generateAhead')}" />
+                                        ${Period.get(1).encodeAsHTML()}
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.generateAhead" />
+                                </td>
+                            </tr>
+                      
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="maxSubTasks">Max Sub Tasks:</label>
+                                </td>
+                                <td valign="top" class="value" >
+                                    <input type="text" class="time ${hasErrors(bean:taskRecurringScheduleInstance,field:'maxSubTasks','errors')}"
+                                        id="maxSubTasks" name="maxSubTasks" value="${fieldValue(bean:taskRecurringScheduleInstance,field:'maxSubTasks')}" />
+                                        <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.maxSubTasks" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="useTargetCompletionDate">Use Target Completion Date:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskRecurringScheduleInstance,field:'useTargetCompletionDate','errors')}">
+                                    <g:checkBox name="useTargetCompletionDate"
+                                                                value="${taskRecurringScheduleInstance?.useTargetCompletionDate}" >
+                                    </g:checkBox>
+                                    <g:helpBalloon class="helpballoon" code="taskRecurringSchedule.useTargetCompletionDate" />
+                                    <g:formatDate date="${taskRecurringScheduleInstance.task.targetCompletionDate}"
+                                                                    format="EEE, dd-MMM-yyyy"/>
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+<!--                     <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span> -->
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/list.gsp	(revision 875)
@@ -0,0 +1,78 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskRecurringSchedule List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New TaskRecurringSchedule</g:link></span>
+        </div>
+        <div class="body">
+            <h1>TaskRecurringSchedule List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="taskId" title="Recurring Schedule for Task" />
+                        
+                   	        <g:sortableColumn property="recurEvery" title="Recur Every" />
+                   	        
+                   	        <g:sortableColumn property="recurPeriod" title="Recur Period" />
+                   	        
+                   	        <g:sortableColumn property="enabled" title="Enabled" />
+
+                            <th></th>
+                   	    
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${taskRecurringScheduleInstanceList}" status="i" var="taskRecurringScheduleInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskRecurringScheduleDetailed/show/${taskRecurringScheduleInstance.id}"'>
+                                ${fieldValue(bean:taskRecurringScheduleInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskRecurringScheduleDetailed/show/${taskRecurringScheduleInstance.id}"'>
+                                ${fieldValue(bean:taskRecurringScheduleInstance, field:'task')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskRecurringScheduleDetailed/show/${taskRecurringScheduleInstance.id}"'>
+                                ${fieldValue(bean:taskRecurringScheduleInstance, field:'recurEvery')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskRecurringScheduleDetailed/show/${taskRecurringScheduleInstance.id}"'>
+                                ${fieldValue(bean:taskRecurringScheduleInstance, field:'recurPeriod')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/taskRecurringScheduleDetailed/show/${taskRecurringScheduleInstance.id}"'>
+                                ${fieldValue(bean:taskRecurringScheduleInstance, field:'enabled')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${taskRecurringScheduleInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${taskRecurringScheduleInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskRecurringScheduleDetailed/show.gsp	(revision 875)
@@ -0,0 +1,167 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskRecurringSchedule</title>
+    </head>
+    <body>
+        <div class="nav">
+            <h1>Show Recurring Schedule</h1>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+                <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+                        <tr class="prop">
+                            <td valign="top" class="name">Recurring Schedule for task:</td>
+
+                            <td valign="top" class="value">
+                                <g:link controller="taskDetailed" action="show" id="${taskRecurringScheduleInstance.task?.id}">
+                                    ${taskRecurringScheduleInstance.task.encodeAsHTML()}
+                                </g:link>
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name"></td>
+
+                            <td valign="top" class="value">${taskRecurringScheduleInstance.encodeAsHTML()}</td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Enabled:</td>
+
+                            <td valign="top" class="value">${fieldValue(bean:taskRecurringScheduleInstance, field:'enabled')}</td>
+                        </tr>
+
+                        <g:if test="${taskRecurringScheduleInstance.useTargetCompletionDate}" >
+                            <tr class="prop">
+                                <td valign="top" class="name">Task Target Completion:</td>
+
+                                <td valign="top" class="value">
+                                    <g:formatDate date="${taskRecurringScheduleInstance.task.targetCompletionDate}"
+                                                                    format="EEE, dd-MMM-yyyy"/>
+                                </td>
+                            </tr>
+                        </g:if>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Next Generation Date:</td>
+
+                            <td valign="top" class="value">
+                                <g:formatDate date="${taskRecurringScheduleInstance.nextGenerationDate}" format="EEE, dd-MMM-yyyy"/>
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Generate Ahead:</td>
+
+                            <td valign="top" class="value">
+                                ${taskRecurringScheduleInstance.generateAhead} ${Period.get(1).encodeAsHTML()}
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Next Target Start Date:</td>
+
+                            <td valign="top" class="value">
+                                <g:formatDate date="${taskRecurringScheduleInstance.nextTargetStartDate}" format="EEE, dd-MMM-yyyy"/>
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Task Duration:</td>
+
+                            <td valign="top" class="value">
+                                ${taskRecurringScheduleInstance.taskDuration} ${taskRecurringScheduleInstance.taskDurationPeriod}
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Next Target Completion Date:</td>
+
+                            <td valign="top" class="value">
+                                <g:formatDate date="${taskRecurringScheduleInstance.nextTargetCompletionDate}" format="EEE, dd-MMM-yyyy"/>
+                            </td>
+                        </tr>
+
+                    </tbody>
+                </table>
+                <table>
+                    <tbody>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Note:</td>
+
+                            <td valign="top" class="value">
+                                Recurring Schedules are reviewed and Sub Tasks generated every ${grailsApplication.config.taskRecurringScheduleJob.repeatInterval.encodeAsHTML()} seconds.
+                            </td>
+                        </tr>
+
+                        <tr class="prop">
+                            <td valign="top" class="name">Sub Tasks Generated:</td>
+
+                            <td valign="top" class="value">
+                                ${fieldValue(bean:taskRecurringScheduleInstance, field:'subTasksGenerated')}
+                            </td>
+                        </tr>
+
+                        <g:if test="${taskRecurringScheduleInstance.maxSubTasks > 0}" >
+                            <tr class="prop">
+                                <td valign="top" class="name">Max Sub Tasks:</td>
+
+                                <td valign="top" class="value">
+                                    ${fieldValue(bean:taskRecurringScheduleInstance, field:'maxSubTasks')}
+                                </td>
+                            </tr>
+                        </g:if>
+
+                        <g:if test="${taskRecurringScheduleInstance.lastGeneratedSubTask}">
+
+                            <tr class="prop">
+                                <td valign="top" class="name">Last Generated Sub Task:</td>
+
+                                <td valign="top" class="value">
+                                    <g:link controller="taskDetailed" action="show" id="${taskRecurringScheduleInstance.lastGeneratedSubTask?.id}">
+                                        ${taskRecurringScheduleInstance.lastGeneratedSubTask?.encodeAsHTML()}
+                                    </g:link>
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name"></td>
+
+                                <td valign="top" class="value">
+                                        ${TaskModification.findByTaskAndTaskModificationType(taskRecurringScheduleInstance.lastGeneratedSubTask, TaskModificationType.get(1))}
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name"></td>
+
+                                <td valign="top" class="value">
+                                        With target start date:
+                                        <g:formatDate date="${taskRecurringScheduleInstance.lastGeneratedSubTask?.targetStartDate}" format="EEE, dd-MMM-yyyy"/>
+                                </td>
+                            </tr>
+
+                        </g:if>
+
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${taskRecurringScheduleInstance.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+<!--                     <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span> -->
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskStatus/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskStatus/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskStatus/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskStatus</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskStatus List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create TaskStatus</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskStatusInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskStatusInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskStatusInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskStatusInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskStatusInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskStatusInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskStatusInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskStatusInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskStatus/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskStatus/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskStatus/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskStatus</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskStatus List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskStatus</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit TaskStatus</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskStatusInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskStatusInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskStatusInstance?.id}" />
+                <input type="hidden" name="version" value="${taskStatusInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskStatusInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskStatusInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskStatusInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskStatusInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskStatusInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskStatusInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="tasks">Tasks:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskStatusInstance,field:'tasks','errors')}">
+                                    
+<ul>
+<g:each var="t" in="${taskStatusInstance?.tasks?}">
+    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="task" params="['taskStatus.id':taskStatusInstance?.id]" action="create">Add Task</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskStatus/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskStatus/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskStatus/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskStatus List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New TaskStatus</g:link></span>
+        </div>
+        <div class="body">
+            <h1>TaskStatus List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${taskStatusInstanceList}" status="i" var="taskStatusInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${taskStatusInstance.id}">${fieldValue(bean:taskStatusInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:taskStatusInstance, field:'name')}</td>
+                        
+                            <td>${fieldValue(bean:taskStatusInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:taskStatusInstance, field:'isActive')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${taskStatusInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskStatus/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskStatus/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskStatus/show.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskStatus</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskStatus List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskStatus</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show TaskStatus</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskStatusInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskStatusInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskStatusInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskStatusInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Tasks:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="t" in="${taskStatusInstance.tasks}">
+                                    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${taskStatusInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskType/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskType/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskType/create.gsp	(revision 875)
@@ -0,0 +1,64 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create TaskType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskType List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create TaskType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskType/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskType/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskType/edit.gsp	(revision 875)
@@ -0,0 +1,84 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit TaskType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit TaskType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <g:hasErrors bean="${taskTypeInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskTypeInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${taskTypeInstance?.id}" />
+                <input type="hidden" name="version" value="${taskTypeInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskTypeInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:taskTypeInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskTypeInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:taskTypeInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskTypeInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${taskTypeInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="tasks">Tasks:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskTypeInstance,field:'tasks','errors')}">
+                                    
+<ul>
+<g:each var="t" in="${taskTypeInstance?.tasks?}">
+    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+</g:each>
+</ul>
+<g:link controller="task" params="['taskType.id':taskTypeInstance?.id]" action="create">Add Task</g:link>
+
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskType/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskType/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskType/list.gsp	(revision 875)
@@ -0,0 +1,55 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>TaskType List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New TaskType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>TaskType List</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${taskTypeInstanceList}" status="i" var="taskTypeInstance">
+                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+                        
+                            <td><g:link action="show" id="${taskTypeInstance.id}">${fieldValue(bean:taskTypeInstance, field:'id')}</g:link></td>
+                        
+                            <td>${fieldValue(bean:taskTypeInstance, field:'name')}</td>
+                        
+                            <td>${fieldValue(bean:taskTypeInstance, field:'description')}</td>
+                        
+                            <td>${fieldValue(bean:taskTypeInstance, field:'isActive')}</td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${taskTypeInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/taskType/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/taskType/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/taskType/show.gsp	(revision 875)
@@ -0,0 +1,77 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskType</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">TaskType List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New TaskType</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show TaskType</h1>
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskTypeInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskTypeInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskTypeInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:taskTypeInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Tasks:</td>
+                            
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="t" in="${taskTypeInstance.tasks}">
+                                    <li><g:link controller="task" action="show" id="${t.id}">${t?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${taskTypeInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/create.gsp	(revision 875)
@@ -0,0 +1,62 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create UnitOfMeasure</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${unitOfMeasureInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${unitOfMeasureInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" >
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:unitOfMeasureInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:unitOfMeasureInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:unitOfMeasureInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:unitOfMeasureInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:unitOfMeasureInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${unitOfMeasureInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/edit.gsp	(revision 875)
@@ -0,0 +1,66 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit UnitOfMeasure</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${unitOfMeasureInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${unitOfMeasureInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" >
+                <input type="hidden" name="id" value="${unitOfMeasureInstance?.id}" />
+                <input type="hidden" name="version" value="${unitOfMeasureInstance?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="name">Name:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:unitOfMeasureInstance,field:'name','errors')}">
+                                    <input type="text" maxlength="50" id="name" name="name" value="${fieldValue(bean:unitOfMeasureInstance,field:'name')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:unitOfMeasureInstance,field:'description','errors')}">
+                                    <input type="text" maxlength="100" id="description" name="description" value="${fieldValue(bean:unitOfMeasureInstance,field:'description')}"/>
+                                </td>
+                            </tr> 
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="isActive">Is Active:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:unitOfMeasureInstance,field:'isActive','errors')}">
+                                    <g:checkBox name="isActive" value="${unitOfMeasureInstance?.isActive}" ></g:checkBox>
+                                </td>
+                            </tr> 
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/list.gsp	(revision 875)
@@ -0,0 +1,69 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>UnitOfMeasure List</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        
+                   	        <g:sortableColumn property="id" title="Id" />
+                        
+                   	        <g:sortableColumn property="name" title="Name" />
+                        
+                   	        <g:sortableColumn property="description" title="Description" />
+                        
+                   	        <g:sortableColumn property="isActive" title="Is Active" />
+
+                            <th></th>
+                        
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="${unitOfMeasureInstanceList}" status="i" var="unitOfMeasureInstance">
+                        <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}">
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/unitOfMeasureDetailed/show/${unitOfMeasureInstance.id}"'>
+                                    ${fieldValue(bean:unitOfMeasureInstance, field:'id')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/unitOfMeasureDetailed/show/${unitOfMeasureInstance.id}"'>
+                                ${fieldValue(bean:unitOfMeasureInstance, field:'name')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/unitOfMeasureDetailed/show/${unitOfMeasureInstance.id}"'>
+                                ${fieldValue(bean:unitOfMeasureInstance, field:'description')}
+                            </td>
+                        
+                            <td onclick='window.location = "${request.getContextPath()}/unitOfMeasureDetailed/show/${unitOfMeasureInstance.id}"'>
+                                ${fieldValue(bean:unitOfMeasureInstance, field:'isActive')}
+                            </td>
+
+                            <td class="notClickable">
+                                <g:link action="show" id="${unitOfMeasureInstance.id}">
+                                    <img  src="${resource(dir:'images/skin',file:'database_go.png')}" alt="Show" />
+                                </g:link>
+                            </td>
+                        
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="${unitOfMeasureInstanceTotal}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/grails-app/views/unitOfMeasureDetailed/show.gsp	(revision 875)
@@ -0,0 +1,61 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show UnitOfMeasure</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Id:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:unitOfMeasureInstance, field:'id')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Name:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:unitOfMeasureInstance, field:'name')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Description:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:unitOfMeasureInstance, field:'description')}</td>
+                            
+                        </tr>
+                    
+                        <tr class="prop">
+                            <td valign="top" class="name">Is Active:</td>
+                            
+                            <td valign="top" class="value">${fieldValue(bean:unitOfMeasureInstance, field:'isActive')}</td>
+                            
+                        </tr>
+                    
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="${unitOfMeasureInstance?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/scripts/UpdateRev.groovy
===================================================================
--- /branches/features/grailsUpgrade/scripts/UpdateRev.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/scripts/UpdateRev.groovy	(revision 875)
@@ -0,0 +1,6 @@
+
+includeTargets << new File("${basedir}/scripts/_UpdateRev.groovy")
+
+target(default: "Update the app.vcsRevision property in application.properties and metadata.") { 
+    depends(updateVcsRevision)
+}
Index: /branches/features/grailsUpgrade/scripts/_Events.groovy
===================================================================
--- /branches/features/grailsUpgrade/scripts/_Events.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/scripts/_Events.groovy	(revision 875)
@@ -0,0 +1,9 @@
+
+includeTargets << new File("${basedir}/scripts/_UpdateRev.groovy")
+
+eventCompileStart = { msg ->
+    if(System.getProperty("grails.env") != "test") {
+        println "Compile started, checking VCS Revision."
+        updateVcsRevision()
+    }
+}
Index: /branches/features/grailsUpgrade/scripts/_UpdateRev.groovy
===================================================================
--- /branches/features/grailsUpgrade/scripts/_UpdateRev.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/scripts/_UpdateRev.groovy	(revision 875)
@@ -0,0 +1,171 @@
+import org.tmatesoft.svn.core.wc.*
+
+//includeTargets << grailsScript("Init")
+
+/**
+* Check and update the app.vcsRevision property in application.properties file and metadata.
+* May be run directly by `grails update-rev` and normally run by _Events.groovy and eventCompileStart.
+* The revision in the properties file is checked against the version control system (VCS) revision
+* and updated if required.
+* The VCS revision is written to the properties file so that it is available in the compiled war.
+* The compile is intentionally allowed to go ahead if a handled exception occurs.
+* VCS currently supported: subversion.
+*/
+target(updateVcsRevision: "Check and update the app.vcsRevision property in application.properties file and metadata.") {
+
+    def result = [:]
+
+    // Properties file.
+    def url = basedir + "/application.properties"
+    def propertiesFile = new File(url)
+
+    def fail = { Map m ->
+        updateInMemoryMetadata('Unknown')
+        def writeResult = writePropertiesFileRevision(propertiesFile, 'Unknown')
+        if(writeResult.error) {
+            m.code= writeResult.error.code
+            m.args= writeResult.error.args
+        }
+
+        result.error = [ code: m.code, args: m.args ]
+        println "Error: UpdateRev script: " + result.error
+        return result
+    }
+
+    // Get propertiesFile revision.
+    def properitesFileResult = getPropertiesFileRevision(propertiesFile)
+    if(properitesFileResult.error)
+        return fail(code: properitesFileResult.error.code, args: properitesFileResult.error.args)
+
+    // Get VCS revision.
+    def vcsResult = getVcsRevision()
+    if(vcsResult.error)
+        return fail(code: vcsResult.error.code, args: vcsResult.error.args)
+
+    // Compare and update.
+    if(properitesFileResult.revision != vcsResult.revision) {
+
+        println "app.vcsRevision = "+properitesFileResult.revision +', VCS Revision = '+vcsResult.revision
+
+        updateInMemoryMetadata(vcsResult.revision)
+
+        // Update application.properties file.
+        def writeResult = writePropertiesFileRevision(propertiesFile, vcsResult.revision)
+        if(writeResult.error)
+            return fail(code: writeResult.error.code, args: writeResult.error.args)
+
+    } // if(rev != rev)
+    else {
+        println "VCS Revisions match: app.vcsRevision = ${properitesFileResult.revision}, VCS Revision = ${vcsResult.revision}."
+    }
+
+    // Success.
+    return result
+
+} // updateVcsRevision()
+
+/**
+* Get the app.vcsRevision property from properties file.
+* @retuns A map containing revision and lineNumber otherwise an error map.
+*/
+def getPropertiesFileRevision(propertiesFile) {
+    def result = [:]
+
+    def fail = { Map m ->
+        result.error = [ code: m.code, args: m.args ]
+        return result
+    }
+
+    if(!propertiesFile.isFile())
+        return fail(code:"application.properties.file.not.found", args:[propertiesFile.getAbsoluteFile()])
+
+    propertiesFile.eachLine { line, lineNumber ->
+        // app.vcsRevision=$Rev: NUM $
+        if ( line =~ '^app.vcsRevision.' ) {
+            if(line.size() > 23) {
+                result.revision = line[22..-3]
+                result.lineNumber = lineNumber
+            }
+        }
+    }
+
+    if(!result.revision || !result.lineNumber)
+        return fail(code:"app.vcsRevision.not.found")
+
+    // Success.
+    return result
+
+} // getAppRevision()
+
+/**
+* Get the working copy's base revision from SVN.
+* @retuns A map containing revision otherwise an error map.
+*/
+def getVcsRevision() {
+    def result = [:]
+
+    def fail = { Map m ->
+        result.error = [ code: m.code, args: m.args ]
+        return result
+    }
+
+    def wc = new File(basedir)
+        if(!wc.isDirectory())
+            return fail(code:"vcs.working.copy.not.found", args:[basedir])
+
+    // Use svnkit to get the base revision.
+    def clientManager = SVNClientManager.newInstance()
+    def wcClient = clientManager.getWCClient()
+    try {
+        result.revision = wcClient.doInfo(wc, SVNRevision.BASE).getRevision().toString()
+    }
+    catch(org.tmatesoft.svn.core.SVNException e) {
+        fail(code:"vcs.exception", args:[e])
+    }
+
+    // Success.
+    return result
+} // getVcsRevision()
+
+/** 
+* Update the in memory metadata if already loaded.
+* Available vars: binding.variables.each { println it.key }
+*/
+def updateInMemoryMetadata(revision) {
+    if(binding.variables.containsKey('metadata')) {
+        def metadata = binding.variables['metadata']
+        metadata['app.vcsRevision'] = '$Rev: '+revision+' $'
+    }
+} // updateInMemoryMetadata()
+
+/**
+* Write revision to properties file.
+* @retuns An error map if any errors.
+*/
+def writePropertiesFileRevision(propertiesFile, revision) {
+    def result = [:]
+
+    def fail = { Map m ->
+        result.error = [ code: m.code, args: m.args ]
+        return result
+    }
+
+    if(!propertiesFile.isFile())
+        return fail(code:"application.properties.file.not.found", args:[propertiesFile.getAbsoluteFile()])
+
+    def revisionString = 'app.vcsRevision=\\$Rev: '+revision+' \\$'
+    println "Updating application.properties file with: ${revisionString}"
+
+    def processFileInplace = { file, Closure processText ->
+        def text = file.text
+        file.write(processText(text))
+    }
+
+    processFileInplace(propertiesFile) { text ->
+        text.replaceAll('app.vcsRevision.*', revisionString)
+    }
+
+    // Success.
+    return result
+
+} // writePropertiesFileRevision()
Index: /branches/features/grailsUpgrade/src/groovy/net/kromhouts/HqlBuilder.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/groovy/net/kromhouts/HqlBuilder.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/groovy/net/kromhouts/HqlBuilder.groovy	(revision 875)
@@ -0,0 +1,482 @@
+/* Copyright 2010 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.kromhouts
+
+/**
+ * Provides a DSL for building and managing HQL strings.
+ * For more usage examples see the HqlBuilderTests.
+ * HQL reference see http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/queryhql.html
+ *
+ * DML reference see http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/batch.html#batch-direct
+ * DML-style clauses: "update, delete, insert into" may not be well tested, the "set" clause has basic implementation.
+ * So double check the q.query output for these cases.
+ *
+ * Primary goals:
+ * 1. Easy to read and understand in code.
+ * 2. Easy to read and understand when printed (e.g when displayed in a report).
+ * 3. Easy to execute with correct paginateParams and namedParams.
+ * 4. Easy to change a clause and execute again.
+ *
+ * Basic usage:
+ *    def q = new HqlBuilder().query {
+ *        select 'count(distinct book)'
+ *        from 'Book as book'
+ *        where 'book.id > 100'
+ *            and 'book.inStock = true'
+ *    }
+ *    def totalCount = Book.executeQuery(q.query, q.namedParams, q.paginateParams)[0].toInteger()
+ *    q.select = 'distinct book'
+ *    def list = Book.executeQuery(q.query, q.namedParams, q.paginateParams)
+ *
+ *    def bookList = new PagedResultList(list, totalCount)
+ *    log.debug '\n' + q.printFormattedQuery
+ *
+ * @author Gavin Kromhout
+ * @version DraftB
+ *
+ */
+class HqlBuilder {
+
+    // HQL clauses.
+    // Each clause is a map key with a list of terms.
+    def clauses = [:]
+
+    // HQL namedParams.
+    // HQL requires the namedParams to match exactly with the clause expressions.
+    def namedParams = [:]
+
+    // HQL paginateParams.
+    def paginateParams = [max: 1000, offset: 0]
+
+    // The where clause terms are handled separately from other clauses
+    // and are a list of logicalTerms.
+    // The where clause is built by buildWhereClause.
+    def whereClauseTerms = []
+
+    // LogicalIndexStack holds indexes of the current whereClauseTerm nesting.
+    def logicalIndexStack = []
+
+   def logicalBuilders = [AND: 'and',
+                                        OR: 'or']
+
+    def nestingStack = []
+
+    // Sort and Order.
+    // It is easier and more flexible to simply add order as a clause, e.g: order 'by name desc, id asc'
+    // def sort = "" // e.g. instanceName.id
+    // def order = "" // e.g. asc or desc
+
+    /**
+     * Constructor.
+     * Any property that exists (or responds) in the class may be supplied as an argument.
+     * E.g: max:20, offset:10, debug:true
+     * The debug property does not really exist, but if true and no external log property
+     * has been setup then the internal mockLogger will be configured in debug mode.
+     *
+     * @param args A map of arguments, defaults to an empty map.
+     *
+     */
+    def HqlBuilder(Map args = [:]) {
+        args.each { arg ->
+            def argKey = arg.key.toLowerCase()
+            if(super.hasProperty(argKey))
+                this[argKey] = arg.value
+        }
+        if(!super.metaClass.hasMetaProperty('log'))
+            mockLogging(args.debug)
+        log.debug "HqlBuilder()"
+    }
+
+    /**
+     * Call with no args.
+     *  Has no real use other than to prevent obscure errors.
+     */
+    def call() {
+        log.debug "call()"
+    }
+
+    /**
+     * Call with closure as last arg.
+     * A typically used build call, e.g: q { } is equivalent to q.call() { }
+     */
+    def call(Closure cl) {
+        log.debug "call(Closure cl)"
+        handleClosure(cl)
+    }
+
+    /**
+     * Domain specific build method.
+     *  Has no real use other than to prevent obscure errors
+     * when user makes a call to query() and Groovy calls query(Closure cl)
+     *
+     * @returns This object.
+     *
+     */
+    def query() {
+        log.debug "query()"
+        return this // Must return this object to q.
+    }
+
+    /**
+     * Domain specific build method.
+     * The recommended build call, e.g: def q = new HqlBuilder().query { }
+     *
+     * @param cl The closure that will be used to build the query.
+     * @returns This object.
+     *
+     */
+    def query(Closure cl) {
+        log.debug "query(Closure cl)"
+        handleClosure(cl)
+        return this // Must return this object to q.
+    }
+
+    /**
+     * InvokeMethod resolves all undefined methods.
+     * Which include the clause methods, e.g: select 'book' is equivalent to select('book').
+     * Note that defined methods will be called directly since this class does not implement GroovyInterceptable.
+     * If class was "HqlBuilder implements GroovyInterceptable" then even println would be intercepted and
+     * several exlusions might be needed. e.g: if(methodName != 'call' && methodName != 'println')
+     */
+    def invokeMethod(String methodName, args) {
+
+        log.debug "invokeMethod(${methodName}, ${args})"
+
+        // Call any closures first, that way the nesting is handled and we just keep a reference.
+        if(args[-1] instanceof Closure) {
+            handleClosure(args[-1], methodName)
+            args = args.minus(args[-1])
+        }
+
+        if(!clauses.containsKey(methodName) && !isLogicalBuilder(methodName))
+            clauses[methodName] = []
+
+        if(args) {
+            if(isWhereClauseBuilder(methodName)) {
+                logicalBuilder(methodName, args)
+                return
+            }
+        }
+
+        for(arg in args) {
+            if(arg instanceof String || arg instanceof GString)
+                clauses[methodName] << arg
+        }
+
+    } // invokeMethod()
+
+    /**
+     * PropertyMissing.
+     * Allows clauses to be added after build, e.g: q.order = 'by book.name asc'
+     * and clauses to be removed, e.g: q.order = null
+     */
+    def propertyMissing(String propertyName, value) {
+        log.debug "propertyMissing(${propertyName}, ${value})"
+
+        if(value == null) {
+            removeClause(propertyName)
+            if(propertyName.toLowerCase() == 'where')
+                whereClauseTerms.clear()
+            return
+        }
+
+        if(!clauses.containsKey(propertyName))
+            clauses[propertyName] = []
+
+        // Occurs when user assigns to where clause, e.g: q.where = 'book.id > 100'
+        if(propertyName.toLowerCase() == 'where') {
+            whereClauseTerms.clear()
+            logicalBuilder(propertyName, [value])
+            return
+        }
+
+        if(value instanceof String || value instanceof GString)
+            clauses[propertyName] = [value]
+    } // propertyMissing(String propertyName, value)
+
+    /**
+     * PropertyMissing.
+     * Allow clauses to be accessed directly by name, e.g: println q.order.
+     * Since clauses is a Map null is simply returned for a non-existant clause.
+     */
+    def propertyMissing(String propertyName) {
+        log.debug "propertyMissing(${propertyName})"
+
+        if(!clauses.containsKey(propertyName))
+            clauses[propertyName] = []
+
+        // Occurs when user performs an operation on where clause.
+        // E.g: q.where << "book.id = 100" which is actually NOT a supported operation since
+        // calling the method provides the correct function e.g: q.where "book.id > 100".
+        // Also allows `println q.where` to be short hand for `println q.whereClauseTerms`
+        if(propertyName.toLowerCase() == 'where') {
+            return whereClauseTerms
+        }
+
+        clauses[propertyName]
+    } // propertyMissing(String propertyName)
+
+    def setMax(Integer value) {
+        paginateParams.max = value
+    }
+
+    def getMax() {
+        paginateParams.max
+    }
+
+    def setOffset(Integer value) {
+        paginateParams.offset = value
+    }
+
+    def getOffset() {
+        paginateParams.offset
+    }
+
+    /**
+     * RemoveClause.
+     * Allows clauses to be removed, e.g: q.removeClause('order')
+     *
+     * @param clauseName The clause to remove.
+     *
+     */
+    def removeClause(String clauseName) {
+            clauses.remove(clauseName)
+    }
+
+    /**
+     * BuildWhereClause.
+     * Build the where clause from whereClauseTerms.
+     */
+    def buildWhereClause(printFormat = false) {
+        //log.debug "buildWhereClause()"
+
+        if(!whereClauseTerms)
+            return ''
+
+        def whereClause = 'where '
+
+        def buildExpression // declared separately to allow recurrsion.
+        buildExpression = { term ->
+            def result = ''
+            def termCount = term.expressions.size()
+            if(termCount > 1) {
+                term.expressions.eachWithIndex { t, index ->
+                    if(index == 0)
+                        result += buildExpression(t)
+                    else if(printFormat)
+                        result += " \n\t${t.logic} ${buildExpression(t)}"
+                    else
+                        result += " ${t.logic} ${buildExpression(t)}"
+
+                }
+                result = "( "+result+" )"
+            }
+            else {
+                if(term.expressions[0] instanceof Map)
+                    result += "${term.expressions[0].expressions[0]}"
+                else
+                    result += "${term.expressions[0]}"
+            }
+            return result
+        }
+
+        whereClauseTerms.eachWithIndex { tm, index ->
+            if(index == 0)
+                whereClause += buildExpression(tm)
+            else if(printFormat)
+                whereClause += " \n\t${tm.logic} ${buildExpression(tm)}"
+            else
+                whereClause += " ${tm.logic} ${buildExpression(tm)}"
+        }
+
+        return whereClause
+    } // buildWhereClause(printFormat = false)
+
+    /**
+     * LogicalBuilder.
+     * Build the whereClauseTerms
+     * by appending logicalTerms to the appropriate expressions.
+     */
+    def logicalBuilder(logicalName, args) {
+        log.debug "logicalBuilder(${logicalName}, ${args})"
+        log.debug "logicalIndexStack: ${logicalIndexStack}"
+
+        def logic = getLogicalString(logicalName)
+
+        for(arg in args) {
+            if(arg instanceof String || arg instanceof GString) {
+                arg = arg.trim()
+                if(arg) { // prevent empty strings being added.
+                    if(logicalIndexStack.size() > 0) {
+                        // Append to current index position.
+                        whereClauseTerms[logicalIndexStack[-1]].expressions << logicalTerm(logic, arg)
+                    }
+                    else {
+                        // Append to 'root'.
+                        whereClauseTerms << logicalTerm(logic, null) // empty expression logicalTerm.
+                        whereClauseTerms[-1].expressions << logicalTerm(logic, arg) // append logicalTerm to expressions
+                    }
+                } // if(arg)
+            } // if(arg instanceof)
+        } // for
+
+    } // logicalBuilder(logicalName, args)
+
+    /**
+     * LogicalTerm.
+     * A logicalTerm is a map object that holds the logic and list of expressions of a whereClauseTerm.
+     */
+    def logicalTerm = { logic, expression ->
+        expression = expression ? [expression] : []
+        ['logic': getLogicalString(logic), 'expressions': expression]
+    }
+
+    /**
+     * GetLogicalString.
+     *
+     * @param logicalName The name to get the matching logicalBuilder string for.
+     */
+    private getLogicalString(logicalName) {
+
+        switch(logicalName.toLowerCase()) {
+            case 'where':
+                logicalBuilders.AND
+                break
+            case logicalBuilders.AND:
+                logicalBuilders.AND
+                break
+            case logicalBuilders.OR:
+                logicalBuilders.OR
+                break
+        }
+
+    }
+
+    /**
+     * HandleClosure.
+     * Setting delegate and DELEGATE_FIRST allows closure to access this object's properties first.
+     */
+    private handleClosure(Closure cl, String methodName = 'root') {
+        log.debug "handleClosure(${cl.toString()}, ${methodName})"
+        if(isWhereClauseBuilder(methodName)) {
+            whereClauseTerms << logicalTerm(getLogicalString(methodName), null)
+            logicalIndexStack << whereClauseTerms.size()-1
+        }
+        nestingStack.push(methodName)
+        cl.delegate = this
+        cl.resolveStrategy = Closure.DELEGATE_FIRST
+        cl.call()
+        //log.debug "nestingStack: $nestingStack"
+        nestingStack.pop()
+        if(isWhereClauseBuilder(methodName)) {
+            logicalIndexStack.pop()
+        }
+    }
+
+    /**
+     * MockLogging.
+     * This class has super cow powers and can mock out it's own debug logging.
+     */
+    private mockLogging(debug = false) {
+        def mockLogger = {}
+        if(debug) {
+            mockLogger = {msg ->
+                    println "${super.getClass()} - DEBUG: $msg"
+            }
+        }
+        super.metaClass.log = [debug: mockLogger]
+        log.debug "Internal mockLogger configured."
+    }
+
+    /**
+     * IsLogicalBuilder.
+     * Determine if a method is a logicalBuilder.
+     */
+    private isLogicalBuilder(String methodName) {
+        logicalBuilders.find{ it.value == methodName.toLowerCase()} ? true:false
+    }
+
+    /**
+     * IsWhereClauseBuilder.
+     * Determine if a method is a where clause builder.
+     */
+    private isWhereClauseBuilder(String methodName) {
+        methodName = methodName.toLowerCase()
+        if(methodName == 'where' || isLogicalBuilder(methodName))
+            return true
+        else
+            return false
+    }
+
+    /**
+     * GetQuery.
+     * Assemble and return the query in a format that can be directly executed.
+     * E.g: executeQuery(q.query, q.namedParams, q.paginateParams).
+     */
+    def getQuery() {
+        clauses.collect { clause ->
+            switch (clause.key.toLowerCase()) {
+                case 'select':
+                    clause.key + ' ' + clause.value.join(', ')
+                    break
+                case 'set':
+                    clause.key + ' ' + clause.value.join(', ')
+                    break
+                case 'where':
+                    buildWhereClause()
+                    break
+                case 'order':
+                    clause.key + ' ' + clause.value.join(', ')
+                    break
+                case 'group':
+                    clause.key + ' ' + clause.value.join(', ')
+                    break
+                default:
+                    clause.key + ' ' + clause.value.join(' ')
+            }
+        }.join(' ')
+    } // getQuery()
+
+    /**
+     * GetPrintFormattedQuery.
+     * Assemble and return the query in a format that can be more easily printed and read by a person.
+     * E.g: println q.printFormattedQuery or when displayed in a report.
+     */
+    def getPrintFormattedQuery() {
+        clauses.collect { clause ->
+            switch (clause.key.toLowerCase()) {
+                case 'select':
+                    clause.key + ' ' + clause.value.join(', \n\t')
+                    break
+                case 'set':
+                    clause.key + ' ' + clause.value.join(', \n\t')
+                    break
+                case 'where':
+                    buildWhereClause(true)
+                    break
+                case 'order':
+                    clause.key + ' ' + clause.value.join(', \n\t')
+                    break
+                case 'group':
+                    clause.key + ' ' + clause.value.join(', \n\t')
+                    break
+                default:
+                    clause.key + ' ' + clause.value.join(' \n\t')
+            }
+        }.join(' \n')
+    } // getPrintFormattedQuery()
+
+} // end class
Index: /branches/features/grailsUpgrade/src/groovy/org/gnumims/RichUiCalendarItem.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/groovy/org/gnumims/RichUiCalendarItem.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/groovy/org/gnumims/RichUiCalendarItem.groovy	(revision 875)
@@ -0,0 +1,13 @@
+package org.gnumims
+
+class RichUiCalendarItem {
+
+    Long id = 0
+    String text = ''
+    Date date = new Date()
+
+    String toString() {
+        "${this.text}"
+    }
+
+}
Index: /branches/features/grailsUpgrade/src/templates/artifacts/Controller.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/Controller.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/Controller.groovy	(revision 875)
@@ -0,0 +1,4 @@
+@artifact.package@class @artifact.name@ {
+
+    def index = { }
+}
Index: /branches/features/grailsUpgrade/src/templates/artifacts/DomainClass.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/DomainClass.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/DomainClass.groovy	(revision 875)
@@ -0,0 +1,5 @@
+@artifact.package@class @artifact.name@ {
+
+    static constraints = {
+    }
+}
Index: /branches/features/grailsUpgrade/src/templates/artifacts/Filters.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/Filters.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/Filters.groovy	(revision 875)
@@ -0,0 +1,17 @@
+@artifact.package@class @artifact.name@ {
+
+    def filters = {
+        all(controller:'*', action:'*') {
+            before = {
+                
+            }
+            after = {
+                
+            }
+            afterView = {
+                
+            }
+        }
+    }
+    
+}
Index: /branches/features/grailsUpgrade/src/templates/artifacts/Script.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/Script.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/Script.groovy	(revision 875)
@@ -0,0 +1,7 @@
+includeTargets << grailsScript("Init")
+
+target(main: "The description of the script goes here!") {
+    // TODO: Implement script here
+}
+
+setDefaultTarget(main)
Index: /branches/features/grailsUpgrade/src/templates/artifacts/Service.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/Service.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/Service.groovy	(revision 875)
@@ -0,0 +1,8 @@
+@artifact.package@class @artifact.name@ {
+
+    boolean transactional = true
+
+    def serviceMethod() {
+
+    }
+}
Index: /branches/features/grailsUpgrade/src/templates/artifacts/TagLib.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/TagLib.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/TagLib.groovy	(revision 875)
@@ -0,0 +1,3 @@
+@artifact.package@class @artifact.name@ {
+
+}
Index: /branches/features/grailsUpgrade/src/templates/artifacts/Tests.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/Tests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/Tests.groovy	(revision 875)
@@ -0,0 +1,15 @@
+@artifact.package@import grails.test.*
+
+class @artifact.name@ extends @artifact.superclass@ {
+    protected void setUp() {
+        super.setUp()
+    }
+
+    protected void tearDown() {
+        super.tearDown()
+    }
+
+    void testSomething() {
+
+    }
+}
Index: /branches/features/grailsUpgrade/src/templates/artifacts/WebTest.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/artifacts/WebTest.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/artifacts/WebTest.groovy	(revision 875)
@@ -0,0 +1,54 @@
+class @webtest.name.caps@Test extends grails.util.WebTest {
+
+    // Unlike unit tests, functional tests are often sequence dependent.
+    // Specify that sequence here.
+    void suite() {
+        test@webtest.name.caps@ListNewDelete()
+        // add tests for more operations here
+    }
+
+    def test@webtest.name.caps@ListNewDelete() {
+        webtest('@webtest.name.caps@ basic operations: view list, create new entry, view, edit, delete, view') {
+            invoke(url:'@webtest.name.lower@')
+            verifyText(text:'Home')
+
+            verifyListPage(0)
+
+            clickLink(label:'New @webtest.name.caps@')
+            verifyText(text:'Create @webtest.name.caps@')
+            clickButton(label:'Create')
+            verifyText(text:'Show @webtest.name.caps@', description:'Detail page')
+            clickLink(label:'List', description:'Back to list view')
+
+            verifyListPage(1)
+
+            group(description:'edit the one element') {
+                clickLink(label:'Show', description:'go to detail view')
+                clickButton(label:'Edit')
+                verifyText(text:'Edit @webtest.name.caps@')
+                clickButton(label:'Update')
+                verifyText(text:'Show @webtest.name.caps@')
+                clickLink(label:'List', description:'Back to list view')
+            }
+
+            verifyListPage(1)
+
+            group(description:'delete the only element') {
+                clickLink(label:'Show', description:'go to detail view')
+                clickButton(label:'Delete')
+                verifyXPath(xpath:"//div[@class='message']", text:/@webtest.name.caps@.*deleted./, regex:true)
+            }
+
+            verifyListPage(0)
+        }
+    }
+
+    String ROW_COUNT_XPATH = "count(//td[@class='actionButtons']/..)"
+
+    def verifyListPage(int count) {
+        ant.group(description:"verify @webtest.name.caps@ list view with $count row(s)") {
+            verifyText(text:'@webtest.name.caps@ List')
+            verifyXPath(xpath:ROW_COUNT_XPATH, text:count, description:"$count row(s) of data expected")
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/src/templates/scaffolding/Controller.groovy
===================================================================
--- /branches/features/grailsUpgrade/src/templates/scaffolding/Controller.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/scaffolding/Controller.groovy	(revision 875)
@@ -0,0 +1,99 @@
+import org.codehaus.groovy.grails.plugins.springsecurity.Secured
+
+<%=packageName ? "package ${packageName}\n\n" : ''%>class ${className}Controller extends BaseAppAdminController {
+    
+    def index = { redirect(action:list,params:params) }
+
+    // the delete, save and update actions only accept POST requests
+    static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+    def list = {
+        params.max = Math.min( params.max ? params.max.toInteger() : 10,  100)
+        [ ${propertyName}List: ${className}.list( params ), ${propertyName}Total: ${className}.count() ]
+    }
+
+    def show = {
+        def ${propertyName} = ${className}.get( params.id )
+
+        if(!${propertyName}) {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:list)
+        }
+        else { return [ ${propertyName} : ${propertyName} ] }
+    }
+
+    def delete = {
+        def ${propertyName} = ${className}.get( params.id )
+        if(${propertyName}) {
+            try {
+                ${propertyName}.delete(flush:true)
+                flash.message = "${className} \${params.id} deleted"
+                redirect(action:list)
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                flash.message = "${className} \${params.id} could not be deleted"
+                redirect(action:show,id:params.id)
+            }
+        }
+        else {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def edit = {
+        def ${propertyName} = ${className}.get( params.id )
+
+        if(!${propertyName}) {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:list)
+        }
+        else {
+            return [ ${propertyName} : ${propertyName} ]
+        }
+    }
+
+    def update = {
+        def ${propertyName} = ${className}.get( params.id )
+        if(${propertyName}) {
+            if(params.version) {
+                def version = params.version.toLong()
+                if(${propertyName}.version > version) {
+                    <%def lowerCaseName = grails.util.GrailsNameUtils.getPropertyName(className)%>
+                    ${propertyName}.errors.rejectValue("version", "default.optimistic.locking.failure")
+                    render(view:'edit',model:[${propertyName}:${propertyName}])
+                    return
+                }
+            }
+            ${propertyName}.properties = params
+            if(!${propertyName}.hasErrors() && ${propertyName}.save(flush: true)) {
+                flash.message = "${className} \${params.id} updated"
+                redirect(action:show,id:${propertyName}.id)
+            }
+            else {
+                render(view:'edit',model:[${propertyName}:${propertyName}])
+            }
+        }
+        else {
+            flash.message = "${className} not found with id \${params.id}"
+            redirect(action:list)
+        }
+    }
+
+    def create = {
+        def ${propertyName} = new ${className}()
+        ${propertyName}.properties = params
+        return ['${propertyName}':${propertyName}]
+    }
+
+    def save = {
+        def ${propertyName} = new ${className}(params)
+        if(!${propertyName}.hasErrors() && ${propertyName}.save(flush: true)) {
+            flash.message = "${className} \${${propertyName}.id} created"
+            redirect(action:show,id:${propertyName}.id)
+        }
+        else {
+            render(view:'create',model:[${propertyName}:${propertyName}])
+        }
+    }
+}
Index: /branches/features/grailsUpgrade/src/templates/scaffolding/create.gsp
===================================================================
--- /branches/features/grailsUpgrade/src/templates/scaffolding/create.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/scaffolding/create.gsp	(revision 875)
@@ -0,0 +1,59 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create ${className}</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Create ${className}</h1>
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="\${${propertyName}}">
+            <div class="errors">
+                <g:renderErrors bean="\${${propertyName}}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form action="save" method="post" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        <%
+
+                            excludedProps = ['version',
+                                             'id',
+                                               Events.ONLOAD_EVENT,
+                                               Events.BEFORE_DELETE_EVENT,
+                                               Events.BEFORE_INSERT_EVENT,
+                                               Events.BEFORE_UPDATE_EVENT]
+                            props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+
+                            Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                            props.each { p ->
+                                if(!Collection.class.isAssignableFrom(p.type)) {
+                                    cp = domainClass.constrainedProperties[p.name]
+                                    display = (cp ? cp.display : true)        
+                                    if(display) { %>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="${p.name}">${p.naturalName}:</label>
+                                </td>
+                                <td valign="top" class="value \${hasErrors(bean:${propertyName},field:'${p.name}','errors')}">
+                                    ${renderEditor(p)}
+                                </td>
+                            </tr> 
+                        <%  }   }   } %>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/src/templates/scaffolding/edit.gsp
===================================================================
--- /branches/features/grailsUpgrade/src/templates/scaffolding/edit.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/scaffolding/edit.gsp	(revision 875)
@@ -0,0 +1,62 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Edit ${className}</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Edit ${className}</h1>
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="\${${propertyName}}">
+            <div class="errors">
+                <g:renderErrors bean="\${${propertyName}}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:form method="post" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
+                <input type="hidden" name="id" value="\${${propertyName}?.id}" />
+                <input type="hidden" name="version" value="\${${propertyName}?.version}" />
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        <%
+                            excludedProps = ['version',
+                                             'id',
+                                               Events.ONLOAD_EVENT,
+                                               Events.BEFORE_DELETE_EVENT,
+                                               Events.BEFORE_INSERT_EVENT,
+                                               Events.BEFORE_UPDATE_EVENT]
+                            props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+                            
+                            Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                            props.each { p ->
+                                cp = domainClass.constrainedProperties[p.name]
+                                display = (cp ? cp.display : true)        
+                                if(display) { %>
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="${p.name}">${p.naturalName}:</label>
+                                </td>
+                                <td valign="top" class="value \${hasErrors(bean:${propertyName},field:'${p.name}','errors')}">
+                                    ${renderEditor(p)}
+                                </td>
+                            </tr> 
+                        <%  }   } %>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/src/templates/scaffolding/list.gsp
===================================================================
--- /branches/features/grailsUpgrade/src/templates/scaffolding/list.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/scaffolding/list.gsp	(revision 875)
@@ -0,0 +1,57 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>${className} List</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+        </div>
+        <div class="body">
+            <h1>${className} List</h1>
+            <g:render template="/shared/messages" />
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                        <%
+                            excludedProps = ['version',
+                                               Events.ONLOAD_EVENT,
+                                               Events.BEFORE_DELETE_EVENT,
+                                               Events.BEFORE_INSERT_EVENT,
+                                               Events.BEFORE_UPDATE_EVENT]
+                            
+                            props = domainClass.properties.findAll { !excludedProps.contains(it.name) && it.type != Set.class }
+                            Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                            props.eachWithIndex { p,i ->
+                   	            if(i < 6) {
+                   	                if(p.isAssociation()) { %>
+                   	        <th>${p.naturalName}</th>
+                   	    <%          } else { %>
+                   	        <g:sortableColumn property="${p.name}" title="${p.naturalName}" />
+                        <%  }   }   } %>
+                        </tr>
+                    </thead>
+                    <tbody>
+                    <g:each in="\${${propertyName}List}" status="i" var="${propertyName}">
+                        <tr class="\${(i % 2) == 0 ? 'odd' : 'even'}">
+                        <%  props.eachWithIndex { p,i ->
+                                if(i == 0) { %>
+                            <td><g:link action="show" id="\${${propertyName}.id}">\${fieldValue(bean:${propertyName}, field:'${p.name}')}</g:link></td>
+                        <%      } else if(i < 6) { %>
+                            <td>\${fieldValue(bean:${propertyName}, field:'${p.name}')}</td>
+                        <%  }   } %>
+                        </tr>
+                    </g:each>
+                    </tbody>
+                </table>
+            </div>
+            <div class="paginateButtons">
+                <g:paginate total="\${${propertyName}Total}" />
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/src/templates/scaffolding/renderEditor.template
===================================================================
--- /branches/features/grailsUpgrade/src/templates/scaffolding/renderEditor.template	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/scaffolding/renderEditor.template	(revision 875)
@@ -0,0 +1,190 @@
+<%  if(property.type == Boolean.class || property.type == boolean.class)
+        out << renderBooleanEditor(domainClass,property)	
+    else if(Number.class.isAssignableFrom(property.type) || (property.type.isPrimitive() && property.type != boolean.class))
+        out << renderNumberEditor(domainClass,property)
+    else if(property.type == String.class)
+        out << renderStringEditor(domainClass,property)
+    else if(property.type == Date.class || property.type == java.sql.Date.class || property.type == java.sql.Time.class)
+        out << renderDateEditor(domainClass,property)
+    else if(property.type == Calendar.class)
+        out << renderDateEditor(domainClass,property)  
+    else if(property.type == URL.class) 
+        out << renderStringEditor(domainClass,property)
+    else if(property.isEnum())
+        out << renderEnumEditor(domainClass,property)
+    else if(property.type == TimeZone.class)
+        out << renderSelectTypeEditor("timeZone",domainClass,property)
+    else if(property.type == Locale.class)
+        out << renderSelectTypeEditor("locale",domainClass,property)
+    else if(property.type == Currency.class)
+        out << renderSelectTypeEditor("currency",domainClass,property)
+    else if(property.type==([] as Byte[]).class) //TODO: Bug in groovy means i have to do this :(
+        out << renderByteArrayEditor(domainClass,property)
+    else if(property.type==([] as byte[]).class) //TODO: Bug in groovy means i have to do this :(
+        out << renderByteArrayEditor(domainClass,property)                
+    else if(property.manyToOne || property.oneToOne)
+        out << renderManyToOne(domainClass,property)
+    else if((property.oneToMany && !property.bidirectional) || (property.manyToMany && property.isOwningSide()))
+        out << renderManyToMany(domainClass, property)
+    else if(property.oneToMany)
+        out << renderOneToMany(domainClass,property)
+
+    private renderEnumEditor(domainClass,property) {
+        if(property.isEnum()) {
+            return "<g:select  from=\"\${${property.type.name}?.values()}\" value=\"\${${domainInstance}?.${property.name}}\" name=\"${property.name}\" ${renderNoSelection(property)}></g:select>"
+        }
+    }
+
+    private renderStringEditor(domainClass, property) {
+        if(!cp) {
+            return "<input type=\"text\" name=\"${property.name}\" id=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+        }
+        else {
+            if("textarea" == cp.widget || (cp.maxSize > 250 && !cp.password && !cp.inList)) {
+                return "<textarea rows=\"5\" cols=\"40\" name=\"${property.name}\">\${fieldValue(bean:${domainInstance}, field:'${property.name}')}</textarea>"
+            }
+             else {
+                if(cp.inList) {
+                    def sb = new StringBuffer('<g:select ')
+                    sb << "id=\"${property.name}\" name=\"${property.name}\" from=\"\${${domainInstance}.constraints.${property.name}.inList}\" value=\"\${${domainInstance}.${property?.name}}\" ${renderNoSelection(property)}>"
+                    sb << '</g:select>'
+                    return sb.toString()
+                }
+                else {
+                    def sb = new StringBuffer('<input ')
+                    cp.password ? sb << 'type="password" ' : sb << 'type="text" '
+                    if(!cp.editable) sb << 'readonly="readonly" '
+                    if(cp.maxSize) sb << "maxlength=\"${cp.maxSize}\" "
+                    sb << "id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\"/>"
+                    return sb.toString()
+                }
+            }
+        }
+    }
+
+    private renderByteArrayEditor(domainClass,property) {
+        return "<input type=\"file\" id=\"${property.name}\" name=\"${property.name}\" />"
+    }
+
+    private renderManyToOne(domainClass,property) {
+        if(property.association) {
+            return "<g:select optionKey=\"id\" from=\"\${${property.type.name}.list()}\" name=\"${property.name}.id\" value=\"\${${domainInstance}?.${property.name}?.id}\" ${renderNoSelection(property)}></g:select>"
+        }
+    }
+
+    private renderManyToMany(domainClass,property) {
+        def sw = new StringWriter()
+        def pw = new PrintWriter(sw)
+
+        pw.println "<g:select name=\"${property.name}\""
+        pw.println "from=\"\${${property.referencedDomainClass.fullName}.list()}\""
+        pw.println "size=\"5\" multiple=\"yes\" optionKey=\"id\""
+        pw.println "value=\"\${${domainInstance}?.${property.name}}\" />"
+
+        return sw.toString()         
+    }
+
+    private renderOneToMany(domainClass,property) {
+        def sw = new StringWriter()
+        def pw = new PrintWriter(sw)
+        pw.println()
+        pw.println "<ul>"
+        pw.println "<g:each var=\"${property.name[0]}\" in=\"\${${domainInstance}?.${property.name}?}\">"
+        pw.println "    <li><g:link controller=\"${property.referencedDomainClass.propertyName}\" action=\"show\" id=\"\${${property.name[0]}.id}\">\${${property.name[0]}?.encodeAsHTML()}</g:link></li>"
+        pw.println "</g:each>"
+        pw.println "</ul>"
+        pw.println "<g:link controller=\"${property.referencedDomainClass.propertyName}\" params=\"['${domainClass.propertyName}.id':${domainInstance}?.id]\" action=\"create\">+Add ${property.referencedDomainClass.shortName}</g:link>"
+        return sw.toString()
+    }
+
+    private renderNumberEditor(domainClass,property) {
+        if(!cp) {
+            if(property.type == Byte.class) {
+                return "<g:select from=\"\${-128..127}\" name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:select>"
+            }
+            else {
+                return "<input type=\"text\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+            }
+        }
+        else {
+            if(cp.range) {
+                return "<g:select from=\"\${${cp.range.from}..${cp.range.to}}\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:select>"
+            }
+            else if(cp.inList) {
+                def sb = new StringBuffer('<g:select ')
+                sb << "id=\"${property.name}\" name=\"${property.name}\" from=\"\${${domainClass.propertyName}.constraints.${property.name}.inList}\" value=\"\${${domainClass.propertyName}.${property?.name}}\" ${renderNoSelection(property)}>"
+                sb << '</g:select>'
+                return sb.toString()
+            }            
+            else {
+                return "<input type=\"text\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+            }
+        }
+     }
+
+    private renderBooleanEditor(domainClass,property) {
+        if(!cp) {
+            return "<g:checkBox name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:checkBox>"
+        }
+        else {
+            def buf = new StringBuffer('<g:checkBox ')
+            if(cp.widget) buf << "widget=\"${cp.widget}\"";
+
+            buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" "
+            cp.attributes.each { k,v ->
+                buf << "${k}=\"${v}\" "
+            }
+            buf << '></g:checkBox>'
+            return buf.toString()
+        }
+    }
+
+    private renderDateEditor(domainClass,property) {
+        def precision = property.type == java.sql.Date ? 'day' : 'minute';
+        if(!cp) {
+            return "<g:datePicker name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" precision=\"${precision}\"></g:datePicker>"
+        }
+        else {
+            if(!cp.editable) {
+                return "\${${domainInstance}?.${property.name}?.toString()}"
+            }
+            else {
+                def buf = new StringBuffer('<g:datePicker ')
+                if(cp.widget) buf << "widget=\"${cp.widget}\" "
+                if(cp.format) buf << "format=\"${cp.format}\" "
+                cp.attributes.each { k,v ->
+                    buf << "${k}=\"${v}\" "
+                }
+                buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" precision=\"${precision}\" ${renderNoSelection(property)}></g:datePicker>"
+                return buf.toString()
+            }
+        }
+    }
+
+    private renderSelectTypeEditor(type,domainClass,property) {
+        if(!cp) {
+            return "<g:${type}Select name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:${type}Select>"
+        }
+        else {
+            def buf = new StringBuffer("<g:${type}Select ")
+            if(cp.widget) buf << "widget=\"${cp.widget}\" ";
+            cp.attributes.each { k,v ->
+                buf << "${k}=\"${v}\" "
+            }
+            buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:${type}Select>"
+            return buf.toString()
+        }
+    }
+
+    private renderNoSelection(property) {
+        if(property.optional) {
+            if(property.manyToOne || property.oneToOne) {
+                return "noSelection=\"['null':'']\""				
+            }
+            else {
+                return "noSelection=\"['':'']\""
+            }
+        }
+        return ""
+    }
+%>
Index: /branches/features/grailsUpgrade/src/templates/scaffolding/show.gsp
===================================================================
--- /branches/features/grailsUpgrade/src/templates/scaffolding/show.gsp	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/scaffolding/show.gsp	(revision 875)
@@ -0,0 +1,61 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show ${className}</title>
+    </head>
+    <body>
+        <div class="nav">
+            <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+            <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+        </div>
+        <div class="body">
+            <h1>Show ${className}</h1>
+            <g:render template="/shared/messages" />
+            <div class="dialog">
+                <table>
+                    <tbody>
+
+                    <%
+                        excludedProps = ['version',
+                                           Events.ONLOAD_EVENT,
+                                           Events.BEFORE_DELETE_EVENT,
+                                           Events.BEFORE_INSERT_EVENT,
+                                           Events.BEFORE_UPDATE_EVENT]
+                        props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+                        Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+                        props.each { p -> %>
+                        <tr class="prop">
+                            <td valign="top" class="name">${p.naturalName}:</td>
+                            <% if(p.isEnum()) { %>
+                            <td valign="top" class="value">\${${propertyName}?.${p.name}?.encodeAsHTML()}</td>
+                            <% } else if(p.oneToMany || p.manyToMany) { %>
+                            <td  valign="top" style="text-align:left;" class="value">
+                                <ul>
+                                <g:each var="${p.name[0]}" in="\${${propertyName}.${p.name}}">
+                                    <li><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${p.name[0]}.id}">\${${p.name[0]}?.encodeAsHTML()}</g:link></li>
+                                </g:each>
+                                </ul>
+                            </td>
+                            <%  } else if(p.manyToOne || p.oneToOne) { %>
+                            <td valign="top" class="value"><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${propertyName}?.${p.name}?.id}">\${${propertyName}?.${p.name}?.encodeAsHTML()}</g:link></td>
+                            <%  } else  { %>
+                            <td valign="top" class="value">\${fieldValue(bean:${propertyName}, field:'${p.name}')}</td>
+                            <%  } %>
+                        </tr>
+                    <%  } %>
+                    </tbody>
+                </table>
+            </div>
+            <div class="buttons">
+                <g:form>
+                    <input type="hidden" name="id" value="\${${propertyName}?.id}" />
+                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+                </g:form>
+            </div>
+        </div>
+    </body>
+</html>
Index: /branches/features/grailsUpgrade/src/templates/war/web.xml
===================================================================
--- /branches/features/grailsUpgrade/src/templates/war/web.xml	(revision 875)
+++ /branches/features/grailsUpgrade/src/templates/war/web.xml	(revision 875)
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+         xmlns="http://java.sun.com/xml/ns/j2ee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+    <display-name>/@grails.project.key@</display-name>
+
+
+    <context-param>
+        <param-name>contextConfigLocation</param-name>
+        <param-value>/WEB-INF/applicationContext.xml</param-value>
+    </context-param>
+
+    <context-param>
+        <param-name>webAppRootKey</param-name>
+        <param-value>@grails.project.key@</param-value>
+    </context-param>
+
+    <filter>
+        <filter-name>sitemesh</filter-name>
+        <filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
+    </filter>
+
+    <filter>
+        <filter-name>charEncodingFilter</filter-name>
+        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+        <init-param>
+            <param-name>targetBeanName</param-name>
+            <param-value>characterEncodingFilter</param-value>
+        </init-param>
+        <init-param>
+            <param-name>targetFilterLifecycle</param-name>
+            <param-value>true</param-value>
+        </init-param>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>charEncodingFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>sitemesh</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <listener>
+        <listener-class>org.codehaus.groovy.grails.web.util.Log4jConfigListener</listener-class>
+    </listener>
+
+    <listener>
+        <listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
+    </listener>
+
+    <!-- Grails dispatcher servlet -->
+    <servlet>
+        <servlet-name>grails</servlet-name>
+        <servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <!-- The Groovy Server Pages servlet -->
+    <servlet>
+        <servlet-name>gsp</servlet-name>
+        <servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>gsp</servlet-name>
+        <url-pattern>*.gsp</url-pattern>
+    </servlet-mapping>
+
+    <welcome-file-list>
+        <!--
+        The order of the welcome pages is important.  JBoss deployment will
+        break if index.gsp is first in the list.
+        -->
+        <welcome-file>index.html</welcome-file>
+        <welcome-file>index.jsp</welcome-file>
+        <welcome-file>index.gsp</welcome-file>
+    </welcome-file-list>
+
+    <jsp-config>
+        <taglib>
+            <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
+            <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
+        </taglib>
+        <taglib>
+            <taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
+            <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
+        </taglib>
+        <taglib>
+            <taglib-uri>http://www.springframework.org/tags</taglib-uri>
+            <taglib-location>/WEB-INF/tld/spring.tld</taglib-location>
+        </taglib>
+        <taglib>
+            <taglib-uri>http://grails.codehaus.org/tags</taglib-uri>
+            <taglib-location>/WEB-INF/tld/grails.tld</taglib-location>
+        </taglib>
+    </jsp-config>
+
+</web-app>
Index: /branches/features/grailsUpgrade/test/integration/CreateDataServiceTests.groovy
===================================================================
--- /branches/features/grailsUpgrade/test/integration/CreateDataServiceTests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/test/integration/CreateDataServiceTests.groovy	(revision 875)
@@ -0,0 +1,108 @@
+import grails.test.*
+
+/**
+* Integration tests for CreateDataService.
+*/
+class CreateDataServiceTests extends GroovyTestCase {
+
+    // By default Grails will rollback the transaction after each test.
+    // Other tests may set this to false so be sure to assert-call-assert.
+    boolean transactional = true
+
+    def appConfigService
+    def createDataService
+
+    // Setup is called before each test.
+    protected void setUp() {
+        super.setUp()
+    }
+
+    // Tear down is called after each test.
+    protected void tearDown() {
+        super.tearDown()
+    }
+
+    void testBaseDataCreated() {
+
+        // Base data should have been created during bootstrap.
+        assertTrue appConfigService.exists("baseDataCreated")
+
+        // Some base data has indeed been created.
+        assert PersonGroupType.count() > 0
+
+    } // testBaseDataCreated()
+
+    void testCreateBaseData() {
+
+        // Base data has already been created in bootstrap,
+        // therefore simply running this will create a host of unique constraint errors
+        // if the method does not exit at the correct point and return false.
+        assertFalse createDataService.createBaseData()
+
+    } // testCreateBaseData()
+
+    void testCreateDemoData() {
+
+        def taskCount
+
+        // No demo tasks yet.
+        taskCount = Task.count()
+        assert taskCount == 0
+
+        // Base data has already been created in bootstrap so
+        // demo data creation should go forward.
+        assertTrue createDataService.createDemoData()
+
+        // Should now have some demo tasks.
+        taskCount = Task.count()
+        assert taskCount > 0
+
+        // Returns false since demo data has already been created.
+        assertFalse createDataService.createDemoData()
+
+        // Task count should not have changed.
+        assert Task.count() == taskCount
+
+    } // testCreateDemoData()
+
+    void testDemoDataCreationDisabled() {
+
+        def taskCount
+
+        // No demo tasks yet.
+        taskCount = Task.count()
+        assert taskCount == 0
+
+        appConfigService.set("demoDataCreationDisabled")
+
+        // False since demo data creation has disabled.
+        assertFalse createDataService.createDemoData()
+
+        // Still no demo tasks.
+        taskCount = Task.count()
+        assert taskCount == 0
+
+    } // testDemoDataCreationDisabled()
+
+    void testCreateDemoDataWithNoBaseData() {
+
+        def taskCount
+
+        // No demo tasks yet.
+        taskCount = Task.count()
+        assert taskCount == 0
+
+        // Base data has already been created in bootstrap so
+        // simulate base data not created.
+        assertTrue appConfigService.delete("baseDataCreated")
+
+        // Returns false since demo data creation has not been recorded.
+        assertFalse createDataService.createDemoData()
+
+        // Still no demo tasks.
+        taskCount = Task.count()
+        assert taskCount == 0
+
+    } // testCreateDemoDataWithNoBaseData()
+
+} // end class
Index: /branches/features/grailsUpgrade/test/integration/TaskSearchServiceTests.groovy
===================================================================
--- /branches/features/grailsUpgrade/test/integration/TaskSearchServiceTests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/test/integration/TaskSearchServiceTests.groovy	(revision 875)
@@ -0,0 +1,219 @@
+import grails.test.*
+
+/**
+* Integration tests for TaskSearchService.
+*/
+class TaskSearchServiceTests extends GroovyTestCase {
+
+    // Data will be saved, not rolled back.
+    // Be sure to clean up in tearDown().
+    boolean transactional = false
+
+    def taskService
+    def dateUtilService
+    def taskSearchService
+    def assignedGroupService
+    def assignedPersonService
+
+    def taskA
+    def taskB
+    def taskCount = 0
+
+    // Setup is called before each test.
+    protected void setUp() {
+        super.setUp()
+
+        // Check environment state.
+        assert Task.count() == 0
+        assert Entry.count() == 0
+        assert TaskModification.count() == 0
+
+        def p = [:]
+        def result
+
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(2),
+                taskType:TaskType.get(1),
+                leadPerson:Person.get(1),
+                description:"TestA",
+                comment:"Service test task.",
+                targetStartDate: dateUtilService.today,
+                targetCompletionDate: dateUtilService.today]
+
+        result = taskService.save(p)
+        assert result.error == null
+        taskCount++
+        taskA = result.taskInstance.refresh()
+
+        p.description = "TestB"
+        result = taskService.save(p)
+        assert result.error == null
+        taskCount++
+        taskB = result.taskInstance.refresh()
+    }
+
+    // Tear down is called after each test.
+    protected void tearDown() {
+
+        taskService.delete(taskA)
+        taskService.delete(taskB)
+
+        // Ensure that we leave environment clean.
+        assert Task.count() == 0
+        assert TaskModification.count() == 0
+        assert Entry.count() == 0
+
+        super.tearDown()
+    }
+
+
+    /**
+    * Test GetTasks.
+    */
+    void testGetTasks() {
+        // Todays tasks should be returned.
+        def tasks = taskSearchService.getTasks([:])
+        assert tasks.totalCount == taskCount
+
+        // Tasks in the trash should not be returned.
+        taskA.trash = true
+        taskA.save(flush:true)
+        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1
+        taskB.trash = true
+        taskB.save(flush:true)
+        assert taskSearchService.getTasks([:]).totalCount == taskCount - 2
+
+        // Restored tasks should be returned.
+        taskA.trash = false
+        taskA.save(flush:true)
+        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1
+        taskB.trash = false
+        taskB.save(flush:true)
+        assert taskSearchService.getTasks([:]).totalCount == taskCount
+
+        // Tomorrows tasks should not be returned.
+        taskA.targetStartDate = dateUtilService.tomorrow
+        taskA.targetCompletionDate = dateUtilService.tomorrow
+        taskA.save(flush:true)
+        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1
+
+        // Tomorrows tasks should be returned, if we ask for them.
+        assert taskSearchService.getTasks([:], dateUtilService.today, dateUtilService.tomorrow+1).totalCount == taskCount
+
+        // Yesterdays tasks should not be returned.
+        taskA.targetStartDate = dateUtilService.yesterday
+        taskA.targetCompletionDate = dateUtilService.yesterday
+        taskA.save(flush:true)
+        assert taskSearchService.getTasks([:]).totalCount == taskCount - 1
+
+        // Yesterdays tasks should be returned, if we ask for them.
+        assert taskSearchService.getTasks([:], dateUtilService.yesterday, dateUtilService.tomorrow).totalCount == taskCount
+
+        // Tasks that span today should be returned.
+        taskA.targetStartDate = dateUtilService.yesterday
+        taskA.targetCompletionDate = dateUtilService.tomorrow
+        taskA.save(flush:true)
+        assert taskSearchService.getTasks([:]).totalCount == taskCount
+    } // testGetTasks()
+
+    /**
+    * Test GetPersonsTasks.
+    */
+    void testGetPersonsTasks() {
+
+        def p = [:]
+        def params = [:]
+
+        // Todays tasks should be returned, since Person #1 is lead and created the tasks.
+        def tasks = taskSearchService.getPersonsTasks(params)
+        assert tasks.totalCount == taskCount
+
+        // Tasks in the trash should not be returned.
+        taskA.trash = true
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1
+        taskB.trash = true
+        taskB.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 2
+
+        // Restored tasks should be returned.
+        taskA.trash = false
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1
+        taskB.trash = false
+        taskB.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount
+
+        // Tomorrows tasks should not be returned.
+        taskA.targetStartDate = dateUtilService.tomorrow
+        taskA.targetCompletionDate = dateUtilService.tomorrow
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1
+
+        // Tomorrows tasks should be returned, if we ask for them.
+        assert taskSearchService.getPersonsTasks(params, null, dateUtilService.today, dateUtilService.tomorrow+1).totalCount == taskCount
+
+        // Yesterdays tasks should not be returned.
+        taskA.targetStartDate = dateUtilService.yesterday
+        taskA.targetCompletionDate = dateUtilService.yesterday
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1
+
+        // Yesterdays tasks should be returned, if we ask for them.
+        assert taskSearchService.getPersonsTasks(params, null, dateUtilService.yesterday, dateUtilService.tomorrow).totalCount == taskCount
+
+        // Tasks that span today should be returned.
+        taskA.targetStartDate = dateUtilService.yesterday
+        taskA.targetCompletionDate = dateUtilService.tomorrow
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount
+
+        // Tasks for a different person should not be returned.
+        taskA.leadPerson = Person.get(2)
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params).totalCount == taskCount - 1
+
+        // Tasks for a specified leadPerson should be returned.
+        // But only if approved since this person did not create the tasks.
+        taskA.leadPerson = Person.get(2)
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 0
+        taskA.approved = true
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 1
+        // Moving the task to the trash, stops it being returned.
+        taskA.trash = true
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 0
+
+        // Tasks assigned to a person should be returned.
+        // But only if approved.
+        p = [person: Person.get(2),
+                task: taskB,
+                estimatedHour: 1,
+                estimatedMinute: 20]
+        assert assignedPersonService.save(p).error == null
+        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 0
+        taskB.approved = true
+        taskB.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 1
+
+        // Tasks assigned to a person via a group should be returned.
+        // But only if approved.
+        Person.get(2).addToPersonGroups(PersonGroup.read(1)).save(flush:true)
+        taskA.trash = false
+        taskA.approved = false
+        taskA.save(flush:true)
+        p = [personGroup: PersonGroup.read(1),
+                task: taskA,
+                estimatedHour: 2,
+                estimatedMinute: 30]
+        assert assignedGroupService.save(p).error == null
+        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 1 // Only taskB from above.
+        taskA.approved = true
+        taskA.save(flush:true)
+        assert taskSearchService.getPersonsTasks(params, Person.get(2)).totalCount == 2 // taskA and taskB.
+
+    } // testGetPersonsTasks()
+
+} // end class
Index: /branches/features/grailsUpgrade/test/integration/TaskServiceTests.groovy
===================================================================
--- /branches/features/grailsUpgrade/test/integration/TaskServiceTests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/test/integration/TaskServiceTests.groovy	(revision 875)
@@ -0,0 +1,217 @@
+import grails.test.*
+
+/**
+* Integration tests for TaskService.
+*/
+class TaskServiceTests extends GroovyTestCase {
+
+    // Data will be saved, not rolled back.
+    // Be sure to clean up in tearDown().
+    boolean transactional = false
+
+    def taskService
+    def dateUtilService
+
+    def taskA
+    def taskB
+    def taskCount = 0
+
+    // Setup is called before each test.
+    protected void setUp() {
+        super.setUp()
+
+        // Check environment state.
+        assert Task.count() == 0
+        assert Entry.count() == 0
+        assert TaskModification.count() == 0
+
+        def p = [:]
+        def result
+
+        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
+                taskPriority:TaskPriority.get(2),
+                taskType:TaskType.get(1),
+                leadPerson:Person.get(1),
+                description:"TestA",
+                comment:"Service test task.",
+                targetStartDate: dateUtilService.today,
+                targetCompletionDate: dateUtilService.today]
+
+        result = taskService.save(p)
+        assert result.error == null
+        taskCount++
+        taskA = result.taskInstance.refresh()
+
+        p.description = "TestB"
+        result = taskService.save(p)
+        assert result.error == null
+        taskCount++
+        taskB = result.taskInstance.refresh()
+    }
+
+    // Tear down is called after each test.
+    protected void tearDown() {
+
+        taskService.delete(taskA)
+        taskService.delete(taskB)
+
+        // Ensure that we leave environment clean.
+        assert Task.count() == 0
+        assert TaskModification.count() == 0
+        assert Entry.count() == 0
+
+        super.tearDown()
+    }
+
+    def testSave() {
+
+        // Task are created by setUp().
+        assert Task.count() == taskCount
+
+        taskA.refresh()
+        assert taskA.taskModifications.size() == 1
+        assert taskA.taskModifications.each() {
+            it.taskModificationType.id == 1 // Created.
+        }
+
+        taskB.refresh()
+        assert taskB.taskModifications.size() == 1
+        assert taskB.taskModifications.each() {
+            it.taskModificationType.id == 1 // Created.
+        }
+
+    } // testSave()
+
+    void testSaveEntry() {
+
+        def entryParams = [:]
+
+        // Work Done Entry, with zero time booked.
+        entryParams = [task: taskA,
+                                        entryType: EntryType.read(3),
+                                        comment: "Test entry.",
+                                        durationHour: 0,
+                                        durationMinute: 0]
+
+        assert taskService.saveEntry(entryParams).error == null
+
+        taskA.refresh()
+        assert taskA.entries.size() ==  1
+
+    } // testSaveEntry()
+
+    void testSavePMEntryHighestSeverityValidation() {
+
+        def entryParams = [:]
+
+        // PM Entry, with no highestSeverity.
+        entryParams = [task: taskA,
+                                        entryType: EntryType.read(6),
+                                        comment: "Test PM Entry.",
+                                        durationHour: 1,
+                                        durationMinute: 0]
+
+        // Saving entry fails.
+        assert taskService.saveEntry(entryParams).error != null
+        taskA.refresh()
+        assert taskA.highestSeverity == null
+        assert taskA.entries.size() ==  0
+        assert taskA.taskStatus.id == 1 // Not Started.
+
+        // Set highestSeverity.
+        def highestSeverity1 = ConditionSeverity.read(1)
+        def highestSeverity2 = ConditionSeverity.read(2)
+        entryParams.highestSeverity = highestSeverity1
+
+        // Saving entry passes.
+        assert taskService.saveEntry(entryParams).error == null
+        taskA.refresh()
+//         assert taskA.highestSeverity.id == highestSeverity1.id //taskA.highestSeverity is null but works in production
+        assert taskA.entries.size() ==  1
+        assert taskA.taskStatus.id == 2 // In Progress.
+
+        // Set a higher severity.
+        entryParams.highestSeverity = highestSeverity2
+
+        // Saving entry passes and task.highestSeverity is updated.
+        assert taskService.saveEntry(entryParams).error == null
+        taskA.refresh()
+//         assert taskA.highestSeverity.id == highestSeverity2.id //taskA.highestSeverity is null but works in production
+        assert taskA.entries.size() ==  2
+        assert taskA.taskStatus.id == 2 // In Progress.
+
+    } // testSaveEntry()
+
+    void testComplete() {
+
+        def modificationCount = 0
+
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(1) // Not Started.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        taskService.complete(taskA)
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(3) // Complete.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+    } // testComplete()
+
+    void testReopen() {
+
+        def entryParams = [:]
+        def modificationCount = 0
+
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(1) // Not Started.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        taskService.complete(taskA)
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(3) // Complete.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        taskService.reopen(taskA)
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(1) // Not Started.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        // Work Done Entry, with zero time booked.
+        entryParams = [task: taskA,
+                                        entryType: EntryType.read(3),
+                                        comment: "Test entry.",
+                                        durationHour: 0,
+                                        durationMinute: 0]
+
+        assert taskService.saveEntry(entryParams).error == null
+
+        taskService.complete(taskA)
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(3) // Complete.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        taskService.reopen(taskA)
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(1) // Not Started.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        // Work Done Entry, with time booked.
+        entryParams.durationMinute = 1
+        assert taskService.saveEntry(entryParams).error == null
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(2) // In Progress.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        taskService.complete(taskA)
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(3) // Complete.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+        taskService.reopen(taskA)
+        taskA.refresh()
+        assert taskA.taskStatus ==  TaskStatus.read(2) // In Progress.
+        assert taskA.taskModifications.size() == ++modificationCount
+
+    } // testReopen()
+
+} // end class
Index: /branches/features/grailsUpgrade/test/unit/AppConfigServiceTests.groovy
===================================================================
--- /branches/features/grailsUpgrade/test/unit/AppConfigServiceTests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/test/unit/AppConfigServiceTests.groovy	(revision 875)
@@ -0,0 +1,110 @@
+import grails.test.*
+
+/**
+* Unit tests for AppConfigService class.
+*/
+class AppConfigServiceTests extends GrailsUnitTestCase {
+
+    // Not automatically injected, assignment is bellow.
+    def appConfigService
+
+    // Some test data.
+    def configName01 = "baseDataCreated"
+    def configName02 = "dateFormat"
+    def configName03 = "blankValue"
+    def blankString = ''
+    def configDefaultValue = "true"
+    def configValue01 = "false"
+    def configValue02= "EEE, dd-MMM-yyyy"
+
+    protected void setUp() {
+        super.setUp()
+
+        // Mock the domain class.
+        mockDomain(AppConfig)
+        mockForConstraintsTests(AppConfig)
+
+        // Mock logging with debug enabled/disabled.
+        mockLogging(AppConfigService, true)
+
+        // Get an instance of the service.
+        appConfigService = new AppConfigService()
+    }
+
+    protected void tearDown() {
+        appConfigService = null
+        super.tearDown()
+    }
+
+    void testSet() {
+
+        // Set returns false for blank name.
+        assert AppConfig.list().size == 0
+        assertFalse appConfigService.set(blankString)
+        assert AppConfig.list().size == 0
+
+        // Set returns true and saves an object.
+        assertTrue appConfigService.set(configName01)
+        assert AppConfig.list().size == 1
+
+        // Set returns true and does not save a new object for existing appConfig.
+        assertTrue appConfigService.set(configName01, configValue01)
+        assert AppConfig.list().size == 1
+
+        // Set returns true and saves different objects.
+        assertTrue appConfigService.set(configName02, configValue02)
+        assert AppConfig.list().size == 2
+
+        // Set returns false when trying to set a blank value.
+        assertFalse appConfigService.set(configName03, blankString)
+        assert AppConfig.list().size == 2
+    }
+
+    void testExists() {
+
+        // Exists returns false for non existant appConfig.
+        assertFalse appConfigService.exists(configName01)
+
+        // Exists returns true for existing appConfig.
+        appConfigService.set(configName01)
+        assertTrue appConfigService.exists(configName01)
+    }
+
+    void testGetValue() {
+
+        // Get returns false for non existant appConfig.
+        assertFalse appConfigService.getValue(configName01)
+
+        // Set default and check that it returns.
+        appConfigService.set(configName01)
+        assert appConfigService.getValue(configName01) == configDefaultValue
+
+        // Set a value and check that it returns.
+        appConfigService.set(configName01, configValue01)
+        assert appConfigService.getValue(configName01) == configValue01
+    }
+
+    void testDelete() {
+
+        // Deleting returns false for non existant appConfig.
+        assert AppConfig.list().size == 0
+        assertFalse appConfigService.delete(configName01)
+
+        // First set.
+        appConfigService.set(configName01)
+        assert AppConfig.list().size == 1
+
+        // Second set.
+        appConfigService.set(configName02, configValue02)
+        assert AppConfig.list().size == 2
+
+        // Delete first set.
+        assertTrue appConfigService.delete(configName01)
+        assert AppConfig.list().size == 1
+
+        // Delete second set.
+        assertTrue appConfigService.delete(configName02)
+        assert AppConfig.list().size == 0
+    }
+
+}
Index: /branches/features/grailsUpgrade/test/unit/DateUtilServiceTests.groovy
===================================================================
--- /branches/features/grailsUpgrade/test/unit/DateUtilServiceTests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/test/unit/DateUtilServiceTests.groovy	(revision 875)
@@ -0,0 +1,15 @@
+import grails.test.*
+
+class DateUtilServiceTests extends GrailsUnitTestCase {
+    protected void setUp() {
+        super.setUp()
+    }
+
+    protected void tearDown() {
+        super.tearDown()
+    }
+
+    void testSomething() {
+
+    }
+}
Index: /branches/features/grailsUpgrade/test/unit/TaskProcedureTests.groovy
===================================================================
--- /branches/features/grailsUpgrade/test/unit/TaskProcedureTests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/test/unit/TaskProcedureTests.groovy	(revision 875)
@@ -0,0 +1,25 @@
+import grails.test.*
+import org.apache.commons.collections.list.LazyList
+
+class TaskProcedureTests extends GrailsUnitTestCase {
+    protected void setUp() {
+        super.setUp()
+    }
+
+    protected void tearDown() {
+        super.tearDown()
+    }
+
+    void testLazyLists() {
+
+        def tp = new TaskProcedure()
+        assert tp.maintenanceActions instanceof ArrayList
+        assert tp.maintenanceActionLazyList instanceof LazyList
+        // MaintenanceActions is still an ArrayList after decoration.
+        // This may be a requirement of other parts of Grails, for example sortableColumn
+        // seems to have issues if it's not.
+        assert tp.maintenanceActions instanceof ArrayList
+        assert ! (tp.maintenanceActions instanceof LazyList)
+
+    }
+}
Index: /branches/features/grailsUpgrade/test/unit/net/kromhouts/HqlBuilderTests.groovy
===================================================================
--- /branches/features/grailsUpgrade/test/unit/net/kromhouts/HqlBuilderTests.groovy	(revision 875)
+++ /branches/features/grailsUpgrade/test/unit/net/kromhouts/HqlBuilderTests.groovy	(revision 875)
@@ -0,0 +1,477 @@
+/* Copyright 2010 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.kromhouts
+
+import org.apache.commons.logging.LogFactory
+
+/**
+ * Unit tests for HqlBuilder class.
+ * GroovyTestCase is used so that class does not depend on Grails as it may be useful outside of Grails.
+ *
+ * @author Gavin Kromhout
+ * @version DraftB
+ *
+ */
+public class HqlBuilderTests extends GroovyTestCase {
+
+    def n = '\n'
+    def t = '\t'
+    def savedMetaClass
+
+    protected void setUp() {
+        super.setUp()
+        savedMetaClass = HqlBuilder.metaClass
+        def emc = new ExpandoMetaClass(HqlBuilder, true, true)
+        emc.log = LogFactory.getLog(getClass())
+        emc.initialize()
+        GroovySystem.metaClassRegistry.setMetaClass(HqlBuilder, emc)
+    }
+
+    protected void tearDown() {
+        GroovySystem.metaClassRegistry.removeMetaClass(HqlBuilder)
+        GroovySystem.metaClassRegistry.setMetaClass(HqlBuilder, savedMetaClass)
+        super.tearDown()
+    }
+
+    void testBasicUsage() {
+
+        def q = new HqlBuilder().query {
+            select 'count(distinct book)'
+            from 'Book as book'
+            where 'book.id > 100'
+        }
+
+        assert q.query == 'select count(distinct book) from Book as book where book.id > 100'
+
+        q.select = 'distinct book'
+        assert q.query == 'select distinct book from Book as book where book.id > 100'
+        assert q.printFormattedQuery == 'select distinct book \nfrom Book as book \nwhere book.id > 100'
+
+    } // testBasicUsage()
+
+    void testBasicUsageAlternateForm() {
+
+        def q = new HqlBuilder()
+
+        q {
+            select 'distinct book'
+            from 'Book as book'
+            where 'book.id > 100'
+        }
+
+        assert q.query == 'select distinct book from Book as book where book.id > 100'
+
+    } // testBasicUsageAlternateForm()
+
+    void testPaginateParams() {
+
+        def q = new HqlBuilder(max: 99, offset: 11).query {
+            select 'distinct book'
+            from 'Book as book'
+            where 'book.id > 100'
+        }
+
+        assert q.max == 99
+        assert q.offset == 11
+
+    } // testPaginateParams()
+
+    void testPaginateParamsAlternateForm() {
+
+        def q = new HqlBuilder().query {
+            max = 99
+            offset = 11
+            select 'distinct book'
+            from 'Book as book'
+            where 'book.id > 100'
+        }
+
+        assert q.max == 99
+        assert q.offset == 11
+
+    } // testPaginateParamsAlternateForm()
+
+    void testNamedParams() {
+        def startId = 13
+        def endId = 23
+
+        def q = new HqlBuilder().query {
+            namedParams.startId = startId
+            select 'distinct book'
+            from 'Book as book'
+            where 'book.id > :startId'
+                and 'book.id < :endId'
+        }
+
+        q.namedParams.endId = endId
+
+        assert q.namedParams.startId == startId
+        assert q.namedParams.endId == endId
+
+    } // testNamedParams()
+
+    void testMultipleTerms() {
+
+        def q = new HqlBuilder().query {
+            select 'book.name',
+                        'type.name'
+            from 'Book as book',
+                    'left join book.group as group',
+                    'left join group.type as type'
+            where "book.name like '%Ned%'",
+                        'group = :group'
+        }
+
+        def expectedQuery = /select book.name, type.name from Book as book left join book.group as group left join group.type as type/
+        expectedQuery +=  / where book.name like '%Ned%' and group = :group/
+        assert q.query == expectedQuery
+
+        def expectedPrintFormat = /select book.name, ${n}${t}type.name/
+        expectedPrintFormat += / ${n}from Book as book ${n}${t}left join book.group as group ${n}${t}left join group.type as type/
+        expectedPrintFormat += / ${n}where book.name like '%Ned%' ${n}${t}and group = :group/
+        assert q.printFormattedQuery == expectedPrintFormat
+
+    } // testMultipleTerms()
+
+    void testMultipleTermsAlternateForm() {
+
+        def q = new HqlBuilder().query {
+            select 'book.name' // Create clause and append arg to clause's term list.
+            select 'type.name' // Method arg is appended to existing clause's term list.
+            from 'Book as book'
+            left 'join book.group as group'
+            left 'left join group.type as type' // 'left join' has to be repeated since left is an existing clause.
+            where(/book.name like '%Ned%'/) // Slashy string literals have to be protected when calling a method.
+            where 'group = :group'
+        }
+
+        def expectedQuery = /select book.name, type.name from Book as book left join book.group as group left join group.type as type/
+        expectedQuery +=  / where book.name like '%Ned%' and group = :group/
+        assert q.query == expectedQuery
+
+        def expectedPrintFormat = /select book.name, ${n}${t}type.name/
+        expectedPrintFormat += / ${n}from Book as book ${n}left join book.group as group ${n}${t}left join group.type as type/
+        expectedPrintFormat += / ${n}where book.name like '%Ned%' ${n}${t}and group = :group/
+        assert q.printFormattedQuery == expectedPrintFormat
+
+    } // testMultipleTermsAlternateForm()
+
+    void testPlaceHolder() {
+
+        def q = new HqlBuilder().query {
+            select 'distinct book'
+            from 'Book as book'
+            where  // Place holder as propertyMissing call.
+            order 'by book.name asc'
+        }
+
+        // Assign to place holder which is in the middle of the query string.
+        q.where = /book.name like '%Ned%'/
+
+        assert q.query == /select distinct book from Book as book where book.name like '%Ned%' order by book.name asc/
+
+    } // testPlaceHolder()
+
+    void testPlaceHolderAlternateForm() {
+
+        def q = new HqlBuilder().query {
+            select 'distinct book'
+            from 'Book as book'
+            where '' // Place holder as method call, tests for nulls when also using append method call bellow.
+            order 'by book.name asc'
+        }
+
+        // Append to place holder which is in the middle of the query string.
+        q.where(/book.name like '%Ned%'/)
+
+        assert q.query == /select distinct book from Book as book where book.name like '%Ned%' order by book.name asc/
+
+    } // testPlaceHolderAlternateForm()
+
+    void testClauseRemoval() {
+
+        def q = new HqlBuilder().query {
+            select 'count(distinct book)'
+            from 'Book as book'
+            where = /book.name like '%Ned%'/  // Slashy string literals don't need protecting when assigning.
+            order 'by book.name asc'
+        }
+
+        q.order = null // Remove clause.
+        assert q.query == /select count(distinct book) from Book as book where book.name like '%Ned%'/
+
+    } // testClauseRemoval()
+
+    void testClauseRemovalAlternateForm() {
+
+        def q = new HqlBuilder().query {
+            select 'count(distinct book)'
+            from 'Book as book'
+            where = /book.name like '%Ned%'/  // Slashy string literals don't need protecting when assigning.
+            order 'by book.name asc'
+        }
+
+        q.removeClause('order') // Remove clause, alternate form.
+        assert q.query == /select count(distinct book) from Book as book where book.name like '%Ned%'/
+
+    } // testClauseRemovalAlternateForm()
+
+    void testLogicalBuilder() {
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where "book.name like '%Ned%'"
+                or "book.onSpecial = true"
+        }
+
+        assert q.query == /from Book as book where book.name like '%Ned%' or book.onSpecial = true/
+
+    } // testLogicalBuilder()
+
+    void testLogicalBuilderNesting() {
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where "book.name like '%Ned%'"
+                or {
+                    where "book.onSpecial = true"
+                    and 'book.inStock = true'
+                }
+        }
+
+        assert q.query == /from Book as book where book.name like '%Ned%' or ( book.onSpecial = true and book.inStock = true )/
+
+    } // testLogicalBuilderNesting()
+
+    void testLogicalBuilderNestingLoop() {
+        def range = 1..2
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where 'book.inStock = true'
+                and {
+                    range.each {
+                        or "book.id = $it"
+                    }
+                }
+        }
+
+        assert q.query == /from Book as book where book.inStock = true and ( book.id = 1 or book.id = 2 )/
+
+    } // testLogicalBuilderNestingLoop()
+
+    void testWhereClosure() {
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where {
+                and 'book.id = 1'
+            }
+        }
+
+        // Only 1 expression so no brackets.
+        assert q.query == /from Book as book where book.id = 1/
+
+    } // testWhereClosure()
+
+    void testWhereClosureAlternate() {
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+        }
+
+        q.where {
+            and 'book.id = 1',
+                    'book.inStock = true'
+        }
+
+        // More than 1 expression so brackets are included.
+        assert q.query == /from Book as book where ( book.id = 1 and book.inStock = true )/
+
+    } // testWhereClosureAlternate()
+
+// This is very likely to be a common usage error as it may seem like a natural way to write the where clause.
+// Is it possible to intercept the String & GString constructors just inside the closure and call where 'book.id = 1'?
+// Perhaps by internally creating a new Closure and using something like this:
+// http://groovy.codehaus.org/JN3515-Interception ???
+// Or is it possible to examine each statement of a closure?
+    void testWhereClosureWithNewString() {
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where {
+                'book.id = 1' // This statement is missing a method call and hence will simply be excluded.
+                and 'book.inStock = true'
+            }
+        }
+
+        // Would be nice if the first case was true.
+        assertFalse q.query == /from Book as book where ( book.id = 1 and book.inStock = true )/
+        assert q.query == /from Book as book where book.inStock = true/
+
+    } // testSelectWhereClosureWithNewString()
+
+    void testWithConditionals() {
+        def y = true
+        def n = false
+
+        def q = new HqlBuilder().query {
+            select 'distinct book'
+            from 'Book as book'
+            if(y)
+                where(/book.name like '%Ned%'/)
+            if(n)
+                order ''
+            else
+                order 'by book.name asc'
+        }
+
+        assert q.query == /select distinct book from Book as book where book.name like '%Ned%' order by book.name asc/
+
+    } // testWithConditionals()
+
+    void testSelectWithLooping() {
+        def selections = ['id', 'name', 'description']
+
+        def q = new HqlBuilder().query {
+            for(s in selections) {
+                select "book.${s}"
+            }
+            from 'Book as book'
+        }
+
+        assert q.query == /select book.id, book.name, book.description from Book as book/
+
+    } // testSelectWithLooping()
+
+    void testWhereWithLooping() {
+        def range = 1..3
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where 'book.inStock = true'
+                range.each {
+                    or "book.id = $it"
+                }
+        }
+
+        assert q.query == /from Book as book where book.inStock = true or book.id = 1 or book.id = 2 or book.id = 3/
+
+    } // testWhereWithLooping()
+
+    void testWhereDirectlyWithLoops() {
+        def range = 1..3
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where
+                range.each {
+                    or "book.id = $it"
+                }
+        }
+
+        assert q.query == /from Book as book where book.id = 1 or book.id = 2 or book.id = 3/
+
+    } // testWhereDirectlyWithLoops()
+
+    void testWhereNodeWithLoops() {
+        def range = 1..3
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where {
+                range.each {
+                    or "book.id = $it"
+                }
+            }
+        }
+
+        assert q.query == /from Book as book where ( book.id = 1 or book.id = 2 or book.id = 3 )/
+
+    } // testWhereNodeWithLoops()
+
+    void testOrderByMultipleTerms() {
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where 'book.id > 100'
+            order 'by book.name asc',
+                        'book.id desc'
+        }
+
+        assert q.query == 'from Book as book where book.id > 100 order by book.name asc, book.id desc'
+
+        assert q.printFormattedQuery == 'from Book as book \nwhere book.id > 100 \norder by book.name asc, \n\tbook.id desc'
+
+    } // testOrderByMultipleTerms()
+
+    void testGroupByMultipleTerms() {
+
+        def q = new HqlBuilder().query {
+            from 'Book as book'
+            where 'book.id > 100'
+            group 'by book.name asc',
+                        'book.id desc'
+        }
+
+        assert q.query == 'from Book as book where book.id > 100 group by book.name asc, book.id desc'
+
+        assert q.printFormattedQuery == 'from Book as book \nwhere book.id > 100 \ngroup by book.name asc, \n\tbook.id desc'
+
+    } // testGroupByMultipleTerms()
+
+    void testUpdate() {
+        def q = new HqlBuilder().query {
+            update 'Book b'
+            set 'b.name = :newName',
+                'b.inStock = true'
+            where 'b.name = :oldName'
+        }
+
+        assert q.query == 'update Book b set b.name = :newName, b.inStock = true where b.name = :oldName'
+
+        assert q.printFormattedQuery == 'update Book b \nset b.name = :newName, \n\tb.inStock = true \nwhere b.name = :oldName'
+
+    } // testUpdate()
+
+    void testDelete() {
+        def q = new HqlBuilder().query {
+            delete 'Book b'
+            where 'b.name = :oldName'
+        }
+
+        assert q.query == 'delete Book b where b.name = :oldName'
+
+        assert q.printFormattedQuery == 'delete Book b \nwhere b.name = :oldName'
+
+    } // testDelete()
+
+    void testInsertInto() {
+        def q = new HqlBuilder().query {
+            insert 'into ArchiveBook (id, name)'
+            select 'b.id',
+                        'b.name'
+            from 'Book b'
+            where 'b.name = :oldName'
+        }
+
+        assert q.query == 'insert into ArchiveBook (id, name) select b.id, b.name from Book b where b.name = :oldName'
+
+        assert q.printFormattedQuery == 'insert into ArchiveBook (id, name) \nselect b.id, \n\tb.name \nfrom Book b \nwhere b.name = :oldName'
+
+    } // testInsertInto()
+
+} // end class
Index: /branches/features/grailsUpgrade/web-app/WEB-INF/applicationContext.xml
===================================================================
--- /branches/features/grailsUpgrade/web-app/WEB-INF/applicationContext.xml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/WEB-INF/applicationContext.xml	(revision 875)
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+	<bean id="grailsApplication" class="org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean">
+		<description>Grails application factory bean</description>
+        <property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
+        <property name="grailsResourceLoader" ref="grailsResourceLoader" />
+	</bean>
+
+	<bean id="pluginManager" class="org.codehaus.groovy.grails.plugins.GrailsPluginManagerFactoryBean">
+		<description>A bean that manages Grails plugins</description>
+        <property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
+        <property name="application" ref="grailsApplication" />
+	</bean>
+
+    <bean id="grailsConfigurator" class="org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator">
+        <constructor-arg>
+            <ref bean="grailsApplication" />
+        </constructor-arg>
+        <property name="pluginManager" ref="pluginManager" />
+    </bean>
+
+    <bean id="grailsResourceLoader" class="org.codehaus.groovy.grails.commons.GrailsResourceLoaderFactoryBean">
+        <property name="grailsResourceHolder" ref="grailsResourceHolder" />
+    </bean>
+
+    <bean id="grailsResourceHolder" scope="prototype" class="org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder">
+        <property name="resources">
+              <value>classpath*:**/grails-app/**/*.groovy</value>
+        </property>
+    </bean>    
+    
+   <bean id="characterEncodingFilter"
+      class="org.springframework.web.filter.CharacterEncodingFilter">
+        <property name="encoding">
+          <value>utf-8</value>
+        </property>
+   </bean>    	
+</beans>
Index: /branches/features/grailsUpgrade/web-app/WEB-INF/sitemesh.xml
===================================================================
--- /branches/features/grailsUpgrade/web-app/WEB-INF/sitemesh.xml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/WEB-INF/sitemesh.xml	(revision 875)
@@ -0,0 +1,14 @@
+<sitemesh>
+    <page-parsers>
+        <parser content-type="text/html"
+            class="org.codehaus.groovy.grails.web.sitemesh.GrailsHTMLPageParser" />
+        <parser content-type="text/html;charset=ISO-8859-1"
+            class="org.codehaus.groovy.grails.web.sitemesh.GrailsHTMLPageParser" />
+        <parser content-type="text/html;charset=UTF-8"
+            class="org.codehaus.groovy.grails.web.sitemesh.GrailsHTMLPageParser" />            
+    </page-parsers>
+
+    <decorator-mappers>
+        <mapper class="org.codehaus.groovy.grails.web.sitemesh.GrailsLayoutDecoratorMapper" />
+    </decorator-mappers>
+</sitemesh>
Index: /branches/features/grailsUpgrade/web-app/WEB-INF/tld/c.tld
===================================================================
--- /branches/features/grailsUpgrade/web-app/WEB-INF/tld/c.tld	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/WEB-INF/tld/c.tld	(revision 875)
@@ -0,0 +1,563 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 core library</description>
+  <display-name>JSTL core</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>c</short-name>
+  <uri>http://java.sun.com/jsp/jstl/core</uri>
+
+  <validator>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlCoreTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Catches any Throwable that occurs in its body and optionally
+        exposes it.
+    </description>
+    <name>catch</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+exception thrown from a nested action. The type of the
+scoped variable is the type of the exception thrown.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Simple conditional tag that establishes a context for
+	mutually exclusive conditional operations, marked by
+	&lt;when&gt; and &lt;otherwise&gt;
+    </description>
+    <name>choose</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+	Simple conditional tag, which evalutes its body if the
+	supplied condition is true and optionally exposes a Boolean
+	scripting variable representing the evaluation of this condition
+    </description>
+    <name>if</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that determines whether or
+not the body content should be processed.
+        </description>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resulting value of the test condition. The type
+of the scoped variable is Boolean.        
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Retrieves an absolute or relative URL and exposes its contents
+        to either the page, a String in 'var', or a Reader in 'varReader'.
+    </description>
+    <name>import</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ImportTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ImportTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The URL of the resource to import.
+        </description>
+        <name>url</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is Reader.
+        </description>
+        <name>varReader</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when accessing a relative
+URL resource that belongs to a foreign
+context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Character encoding of the content at the input
+resource.
+        </description>
+        <name>charEncoding</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	The basic iteration tag, accepting many different
+        collection types and supporting subsetting and other
+        functionality
+    </description>
+    <name>forEach</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
+    <tei-class>org.apache.taglibs.standard.tei.ForEachTEI</tei-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Collection of items to iterate over.
+        </description>
+	<name>items</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.Object</type>
+    </attribute>
+    <attribute>
+        <description>
+If items specified:
+Iteration begins at the item located at the
+specified index. First item of the collection has
+index 0.
+If items not specified:
+Iteration begins with index set at the value
+specified.
+        </description>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+If items specified:
+Iteration ends at the item located at the
+specified index (inclusive).
+If items not specified:
+Iteration ends when index reaches the value
+specified.
+        </description>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration will only process every step items of
+the collection, starting with the first one.
+        </description>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility. Its type depends
+on the object of the underlying collection.
+        </description>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of type
+javax.servlet.jsp.jstl.core.LoopTagStatus. This scoped variable has nested
+visibility.
+        </description>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Iterates over tokens, separated by the supplied delimeters
+    </description>
+    <name>forTokens</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForTokensTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+String of tokens to iterate over.
+        </description>
+	<name>items</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+        <description>
+The set of delimiters (the characters that
+separate the tokens in the string).
+        </description>
+	<name>delims</name>
+	<required>true</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>java.lang.String</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration begins at the token located at the
+specified index. First token has index 0.
+        </description>
+	<name>begin</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration ends at the token located at the
+specified index (inclusive).
+        </description>
+	<name>end</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Iteration will only process every step tokens
+of the string, starting with the first one.
+        </description>
+	<name>step</name>
+	<required>false</required>
+	<rtexprvalue>true</rtexprvalue>
+	<type>int</type>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility.
+        </description>
+	<name>var</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of
+type
+javax.servlet.jsp.jstl.core.LoopTag
+Status. This scoped variable has nested
+visibility.
+        </description>
+	<name>varStatus</name>
+	<required>false</required>
+	<rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Like &lt;%= ... &gt;, but for expressions.
+    </description> 
+    <name>out</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Expression to be evaluated.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Default value if the resulting value is null.
+        </description>
+        <name>default</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Determines whether characters &lt;,&gt;,&amp;,'," in the
+resulting string should be converted to their
+corresponding character entity codes. Default value is
+true.
+        </description>
+        <name>escapeXml</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+
+  <tag>
+    <description>
+        Subtag of &lt;choose&gt; that follows &lt;when&gt; tags
+        and runs only if all of the prior conditions evaluated to
+        'false'
+    </description>
+    <name>otherwise</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <body-content>JSP</body-content>
+  </tag>
+
+  <tag>
+    <description>
+        Adds a parameter to a containing 'import' tag's URL.
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the query string parameter.
+        </description>
+        <name>name</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Value of the parameter.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Redirects to a new URL.
+    </description>
+    <name>redirect</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.RedirectTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The URL of the resource to redirect to.
+        </description>
+        <name>url</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when redirecting to a relative URL
+resource that belongs to a foreign context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Removes a scoped variable (from a particular scope, if specified).
+    </description>
+    <name>remove</name>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of the scoped variable to be removed.
+        </description>
+        <name>var</name>
+        <required>true</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+ <tag>
+    <description>
+        Sets the result of an expression evaluation in a 'scope'
+    </description>
+    <name>set</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.SetTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable to hold the value
+specified in the action. The type of the scoped variable is
+whatever type the value expression evaluates to.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Expression to be evaluated.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Target object whose property will be set. Must evaluate to
+a JavaBeans object with setter property property, or to a
+java.util.Map object.
+        </description>
+        <name>target</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the property to be set in the target object.
+        </description>
+        <name>property</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Creates a URL with optional query parameters.
+    </description>
+    <name>url</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.UrlTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Name of the exported scoped variable for the
+processed url. The type of the scoped variable is
+String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope for var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+URL to be processed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the context when specifying a relative URL
+resource that belongs to a foreign context.
+        </description>
+        <name>context</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+	Subtag of &lt;choose&gt; that includes its body if its
+	condition evalutes to 'true'
+    </description>
+    <name>when</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The test condition that determines whether or not the
+body content should be processed.
+        </description>
+        <name>test</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+	<type>boolean</type>
+    </attribute>
+  </tag>
+
+</taglib>
Index: /branches/features/grailsUpgrade/web-app/WEB-INF/tld/fmt.tld
===================================================================
--- /branches/features/grailsUpgrade/web-app/WEB-INF/tld/fmt.tld	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/WEB-INF/tld/fmt.tld	(revision 875)
@@ -0,0 +1,671 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+    version="2.0">
+    
+  <description>JSTL 1.1 i18n-capable formatting library</description>
+  <display-name>JSTL fmt</display-name>
+  <tlib-version>1.1</tlib-version>
+  <short-name>fmt</short-name>
+  <uri>http://java.sun.com/jsp/jstl/fmt</uri>
+
+  <validator>
+    <description>
+        Provides core validation features for JSTL tags.
+    </description>
+    <validator-class>
+        org.apache.taglibs.standard.tlv.JstlFmtTLV
+    </validator-class>
+  </validator>
+
+  <tag>
+    <description>
+        Sets the request character encoding
+    </description>
+    <name>requestEncoding</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.RequestEncodingTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Name of character encoding to be applied when
+decoding request parameters.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Stores the given locale in the locale configuration variable
+    </description>
+    <name>setLocale</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetLocaleTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+A String value is interpreted as the
+printable representation of a locale, which
+must contain a two-letter (lower-case)
+language code (as defined by ISO-639),
+and may contain a two-letter (upper-case)
+country code (as defined by ISO-3166).
+Language and country codes must be
+separated by hyphen (-) or underscore
+(_).        
+	</description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Vendor- or browser-specific variant.
+See the java.util.Locale javadocs for
+more information on variants.
+        </description>
+        <name>variant</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of the locale configuration variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Specifies the time zone for any time formatting or parsing actions
+        nested in its body
+    </description>
+    <name>timeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.TimeZoneTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See
+java.util.TimeZone for more information on
+supported time zone formats.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Stores the given time zone in the time zone configuration variable
+    </description>
+    <name>setTimeZone</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetTimeZoneTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See java.util.TimeZone for
+more information on supported time zone
+formats.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the time zone of type
+java.util.TimeZone.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var or the time zone configuration
+variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Loads a resource bundle to be used by its tag body
+    </description>
+    <name>bundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.BundleTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+        </description>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Prefix to be prepended to the value of the message
+key of any nested &lt;fmt:message&gt; action.
+        </description>
+        <name>prefix</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Loads a resource bundle and stores it in the named scoped variable or
+        the bundle configuration variable
+    </description>
+    <name>setBundle</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetBundleTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+        </description>
+        <name>basename</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which stores
+the i18n localization context of type
+javax.servlet.jsp.jstl.fmt.LocalizationC
+ontext.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var or the localization context
+configuration variable.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Maps key to localized message and performs parametric replacement
+    </description>
+    <name>message</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.MessageTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Message key to be looked up.
+        </description>
+        <name>key</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Localization context in whose resource
+bundle the message key is looked up.
+        </description>
+        <name>bundle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable
+which stores the localized message.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Supplies an argument for parametric replacement to a containing
+        &lt;message&gt; tag
+    </description>
+    <name>param</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParamTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Argument used for parametric replacement.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Formats a numeric value as a number, currency, or percentage
+    </description>
+    <name>formatNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Numeric value to be formatted.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the value is to be
+formatted as number, currency, or
+percentage.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+ISO 4217 currency code. Applied only
+when formatting currencies (i.e. if type is
+equal to "currency"); ignored otherwise.
+        </description>
+        <name>currencyCode</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Currency symbol. Applied only when
+formatting currencies (i.e. if type is equal
+to "currency"); ignored otherwise.
+        </description>
+        <name>currencySymbol</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the formatted output
+will contain any grouping separators.
+        </description>
+        <name>groupingUsed</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Maximum number of digits in the integer
+portion of the formatted output.
+        </description>
+        <name>maxIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Minimum number of digits in the integer
+portion of the formatted output.
+        </description>
+        <name>minIntegerDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Maximum number of digits in the
+fractional portion of the formatted output.
+        </description>
+        <name>maxFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Minimum number of digits in the
+fractional portion of the formatted output.
+        </description>
+        <name>minFractionDigits</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable
+which stores the formatted result as a
+String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Parses the string representation of a number, currency, or percentage
+    </description>
+    <name>parseNumber</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseNumberTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+String to be parsed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the string in the value
+attribute should be parsed as a number,
+currency, or percentage.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern that determines
+how the string in the value attribute is to be
+parsed.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Locale whose default formatting pattern (for
+numbers, currencies, or percentages,
+respectively) is to be used during the parse
+operation, or to which the pattern specified
+via the pattern attribute (if present) is
+applied.
+        </description>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether just the integer portion of
+the given value should be parsed.
+        </description>
+        <name>integerOnly</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the parsed result (of type
+java.lang.Number).
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Formats a date and/or time using the supplied styles and pattern
+    </description>
+    <name>formatDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatDateTag</tag-class>
+    <body-content>empty</body-content>
+    <attribute>
+        <description>
+Date and/or time to be formatted.
+        </description>
+        <name>value</name>
+        <required>true</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the time, the date, or both
+the time and date components of the given
+date are to be formatted. 
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for dates. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a date or both a date and
+time (i.e. if type is missing or is equal to
+"date" or "both"); ignored otherwise.
+        </description>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for times. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a time or both a date and
+time (i.e. if type is equal to "time" or "both");
+ignored otherwise.
+        </description>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting style for dates and times.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Time zone in which to represent the formatted
+time.
+        </description>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable which
+stores the formatted result as a String.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+  <tag>
+    <description>
+        Parses the string representation of a date and/or time
+    </description>
+    <name>parseDate</name>
+    <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseDateTag</tag-class>
+    <body-content>JSP</body-content>
+    <attribute>
+        <description>
+Date string to be parsed.
+        </description>
+        <name>value</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Specifies whether the date string in the
+value attribute is supposed to contain a
+time, a date, or both.
+        </description>
+        <name>type</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting style for days
+which determines how the date
+component of the date string is to be
+parsed. Applied only when formatting a
+date or both a date and time (i.e. if type
+is missing or is equal to "date" or "both");
+ignored otherwise.
+        </description>
+        <name>dateStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Predefined formatting styles for times
+which determines how the time
+component in the date string is to be
+parsed. Applied only when formatting a
+time or both a date and time (i.e. if type
+is equal to "time" or "both"); ignored
+otherwise.
+        </description>
+        <name>timeStyle</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Custom formatting pattern which
+determines how the date string is to be
+parsed.
+        </description>
+        <name>pattern</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Time zone in which to interpret any time
+information in the date string.
+        </description>
+        <name>timeZone</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Locale whose predefined formatting styles
+for dates and times are to be used during
+the parse operation, or to which the
+pattern specified via the pattern
+attribute (if present) is applied.
+        </description>
+        <name>parseLocale</name>
+        <required>false</required>
+        <rtexprvalue>true</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Name of the exported scoped variable in
+which the parsing result (of type
+java.util.Date) is stored.
+        </description>
+        <name>var</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+    <attribute>
+        <description>
+Scope of var.
+        </description>
+        <name>scope</name>
+        <required>false</required>
+        <rtexprvalue>false</rtexprvalue>
+    </attribute>
+  </tag>
+
+</taglib>
Index: /branches/features/grailsUpgrade/web-app/WEB-INF/tld/grails.tld
===================================================================
--- /branches/features/grailsUpgrade/web-app/WEB-INF/tld/grails.tld	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/WEB-INF/tld/grails.tld	(revision 875)
@@ -0,0 +1,551 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
+            http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+        version="2.0">
+    <description>The Grails (Groovy on Rails) custom tag library</description>
+    <tlib-version>0.2</tlib-version>
+    <short-name>grails</short-name>
+    <uri>http://grails.codehaus.org/tags</uri>
+
+
+    <tag>
+        <name>link</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>action</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>controller</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>id</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>url</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>params</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>form</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspFormTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>action</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>controller</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>id</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>url</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>method</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>select</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspSelectTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>name</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>value</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>optionKey</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>optionValue</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>datePicker</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspDatePickerTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>name</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>value</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>precision</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>false</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>currencySelect</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspCurrencySelectTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>name</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>value</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>localeSelect</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspLocaleSelectTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>name</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>value</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>timeZoneSelect</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspTimeZoneSelectTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>name</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>value</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>checkBox</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspCheckboxTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>name</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>value</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>hasErrors</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspHasErrorsTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>model</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>bean</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>field</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>false</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>eachError</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspEachErrorTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>model</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>bean</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>field</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>false</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>renderErrors</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspEachErrorTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>model</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>bean</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>field</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>as</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>false</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>message</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspMessageTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>code</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>error</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>default</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>false</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>remoteFunction</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspRemoteFunctionTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>before</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>after</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>action</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>controller</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>id</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>url</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>params</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>asynchronous</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>method</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>update</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onSuccess</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onFailure</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onComplete</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onLoading</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onLoaded</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onInteractive</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>remoteLink</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspRemoteLinkTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>before</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>after</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>action</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>controller</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>id</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>url</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>params</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>asynchronous</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>method</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>update</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onSuccess</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onFailure</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onComplete</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onLoading</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onLoaded</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onInteractive</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>formRemote</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspFormRemoteTag</tag-class>
+        <body-content>JSP</body-content>
+        <attribute>
+            <name>before</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>after</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>action</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>controller</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>id</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>url</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>params</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>asynchronous</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>method</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>update</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onSuccess</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onFailure</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onComplete</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onLoading</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onLoaded</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <attribute>
+            <name>onInteractive</name>
+            <required>false</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <tag>
+        <name>invokeTag</name>
+        <tag-class>org.codehaus.groovy.grails.web.taglib.jsp.JspInvokeGrailsTagLibTag</tag-class>
+        <body-content>JSP</body-content>
+        <variable>
+            <name-given>it</name-given>
+            <variable-class>java.lang.Object</variable-class>
+            <declare>true</declare>
+            <scope>NESTED</scope>
+        </variable>
+        <attribute>
+            <name>tagName</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+        <dynamic-attributes>true</dynamic-attributes>
+    </tag>
+</taglib>
+
Index: /branches/features/grailsUpgrade/web-app/WEB-INF/tld/spring.tld
===================================================================
--- /branches/features/grailsUpgrade/web-app/WEB-INF/tld/spring.tld	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/WEB-INF/tld/spring.tld	(revision 875)
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+
+<taglib>
+
+	<tlib-version>1.1.1</tlib-version>
+
+	<jsp-version>1.2</jsp-version>
+
+	<short-name>Spring</short-name>
+
+	<uri>http://www.springframework.org/tags</uri>
+
+	<description>Spring Framework JSP Tag Library. Authors: Rod Johnson, Juergen Hoeller</description>
+
+
+	<tag>
+
+		<name>htmlEscape</name>
+		<tag-class>org.springframework.web.servlet.tags.HtmlEscapeTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Sets default HTML escape value for the current page.
+			Overrides a "defaultHtmlEscape" context-param in web.xml, if any.
+		</description>
+
+		<attribute>
+			<name>defaultHtmlEscape</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>escapeBody</name>
+		<tag-class>org.springframework.web.servlet.tags.EscapeBodyTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Escapes its enclosed body content, applying HTML escaping and/or JavaScript escaping.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>message</name>
+		<tag-class>org.springframework.web.servlet.tags.MessageTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Retrieves the message with the given code, or text if code isn't resolvable.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>code</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>arguments</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>text</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>theme</name>
+		<tag-class>org.springframework.web.servlet.tags.ThemeTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Retrieves the theme message with the given code, or text if code isn't resolvable.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>code</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>arguments</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>text</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>hasBindErrors</name>
+		<tag-class>org.springframework.web.servlet.tags.BindErrorsTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Provides Errors instance in case of bind errors.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<variable>
+			<name-given>errors</name-given>
+			<variable-class>org.springframework.validation.Errors</variable-class>
+		</variable>
+
+		<attribute>
+			<name>name</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>nestedPath</name>
+		<tag-class>org.springframework.web.servlet.tags.NestedPathTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Sets a nested path to be used by the bind tag's path.
+		</description>
+
+		<variable>
+			<name-given>nestedPath</name-given>
+			<variable-class>java.lang.String</variable-class>
+		</variable>
+
+		<attribute>
+			<name>path</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>bind</name>
+		<tag-class>org.springframework.web.servlet.tags.BindTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Provides BindStatus object for the given bind path.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<variable>
+			<name-given>status</name-given>
+			<variable-class>org.springframework.web.servlet.support.BindStatus</variable-class>
+		</variable>
+
+		<attribute>
+			<name>path</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>ignoreNestedPath</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>transform</name>
+		<tag-class>org.springframework.web.servlet.tags.TransformTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Provides transformation of variables to Strings, using an appropriate
+			custom PropertyEditor from BindTag (can only be used inside BindTag).
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>value</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+</taglib>
Index: /branches/features/grailsUpgrade/web-app/css/calendarmonthviewCustom.css
===================================================================
--- /branches/features/grailsUpgrade/web-app/css/calendarmonthviewCustom.css	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/css/calendarmonthviewCustom.css	(revision 875)
@@ -0,0 +1,78 @@
+/* Calendar */
+
+/* Link size and color */
+.calendar a {
+    font-weight: normal;
+    font-size: 12px;
+    color: #000000;
+    text-decoration: none;
+}
+
+.calendar li:hover a{
+    color: red;
+}
+
+.calendar li:hover {
+    color: red;
+}
+
+/* Table  */
+table.calendar td.dayWithItems {
+    background: #ffed8c;
+    border: 1px solid #ffde33;
+}
+table.calendar td.outsideOfMonth {
+    background: #BBBBBB;
+}
+
+table.calendar td.today {
+    background: #B2D1FF;
+}
+
+table.calendar .oddDay {
+    background: #efefef;
+}
+
+table.calendar .evenDay {
+    background: #f7f7f7;
+}
+
+table.calendar td.day {
+    /*
+    height: 12.5%;
+    width: 12.5%;
+    */
+    height: 7em;
+    width: 7em;
+}
+
+table.calendar td.weekOfYear {
+    height: 5%;
+    width: 5%;
+}
+
+/* Day title */
+table.calendar h1 {
+    color:#5C5C5C;
+}
+table.calendar h1:hover {
+    color: red;
+}
+
+table.calendar th:hover, table.calendar td:hover {
+
+}
+
+table.calendar {
+    border-collapse: collapse;
+}
+
+table.calendar th, table.calendar td {
+    border-left:1px solid #DDDDDD;
+}
+
+/* Month Control Title*/
+span.calendarMonthControlTitle {
+    font-size: 17px;
+    font-weight: bold;
+}
Index: /branches/features/grailsUpgrade/web-app/css/lightbox.css
===================================================================
--- /branches/features/grailsUpgrade/web-app/css/lightbox.css	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/css/lightbox.css	(revision 875)
@@ -0,0 +1,88 @@
+#lightbox {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  text-align: center;
+  line-height: 0;
+  overflow: auto;
+  z-index: 100;
+}
+
+#lightbox a img { border: none; }
+
+#outerImageContainer {
+  position: relative;
+  background-color: #fff;
+  width: 250px;
+  height: 250px;
+  margin: 0 auto;
+}
+
+#imageContainer {
+  padding: 10px;
+}
+
+#loading {
+  position: absolute;
+  top: 40%;
+  left: 0%;
+  height: 25%;
+  width: 100%;
+  text-align: center;
+  line-height: 0;
+  background: transparent url("../images/loading.gif") center center no-repeat;
+}
+
+#hoverNav {
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 100%;
+    width: 100%;
+    z-index: 10;
+}
+
+#imageContainer > #hoverNav { left: 0; }
+#hoverNav a { outline: none; }
+
+#prevLink, #nextLink {
+  width: 49%;
+  height: 100%;
+  background: transparent url("../images/blank.gif") no-repeat; /* Trick IE into showing hover */
+  display: block;
+}
+#prevLink { left: 0; float: left; }
+#nextLink { right: 0; float: right; }
+#prevLink:hover, #prevLink:visited:hover { background: url("../images/prevlabel.gif") left 15% no-repeat; }
+#nextLink:hover, #nextLink:visited:hover { background: url("../images/nextlabel.gif") right 15% no-repeat; }
+
+#imageDataContainer {
+  font: 10px Verdana, Helvetica, sans-serif;
+  background-color: #fff;
+  margin: 0 auto;
+  line-height: 1.4em;
+  width: 100%
+}
+
+#imageData { padding: 0 10px; color: #666; text-align: center; }
+#imageData #imageDetails { float: left; text-align: left; }	
+#imageData #caption { font-weight: bold; }
+#imageData #numberDisplay { display: block; clear: left; padding-bottom: 1.0em;	}			
+#imageData #bottomNav { float: right; text-align: right; } 
+
+#imageData #bottomNavClose { cursor: pointer; }
+
+#imageData #bottomNavNext, #imageData #bottomNavPrev { 
+  cursor: pointer;
+  padding: 5px 2px;
+}
+
+#overlay {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 90;
+  width: 100%;
+  height: 500px;
+  background-color: #000;
+}
Index: /branches/features/grailsUpgrade/web-app/css/main.css
===================================================================
--- /branches/features/grailsUpgrade/web-app/css/main.css	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/css/main.css	(revision 875)
@@ -0,0 +1,770 @@
+html * {
+    margin: 0;
+    /*padding: 0; SELECT NOT DISPLAYED CORRECTLY IN FIREFOX */
+
+}
+
+/**
+* GENERAL.
+* Commonly used application colours:
+* #FF9900 - Traffic Light Amber.
+* #00CC00 - Traffic Light Green.
+* #FF0000 - Traffic Light Red.
+* #2647A0 - Dark Blue (Tabs).
+* #006DBA - Link Blue (Links and Message Text).
+* #CC0000 - Dark Red (Error Message Text).
+* #FCFCFC - Off White (Input Fields).
+* #666666 - Dark Grey (Nav Text).
+* #333333 - Very Dark Grey (TH, Menu Button).
+* #FFFFFF - Table Row (Even).
+* #F7F7F7 - Table Row (Odd).
+* #EDEDED - Total Row Grey (Bg).
+* #555555 - Total Row Grey (Fg).
+*/
+
+.spinner {
+    padding: 10px 0 0 18px;
+    position: absolute;
+}
+
+div.app_help {
+    float: right;
+}
+div.app_help a {
+}
+div.app_help img {
+    padding: 0.3em 0.7em 0 0.3em;
+}
+div.app_help img:hover {
+    padding: 0.5em 0.7em 0 0.3em;
+}
+
+body {
+    text-align: center;
+    color: #222;
+    font: 14px verdana, arial, helvetica, sans-serif;
+    background: transparent url("../images/brushed_metal.png") repeat fixed center;
+}
+
+#wrapper {
+  margin: 0 auto;
+  padding: 0;
+  width: 1024px;
+}
+
+#top {
+  background: url("../images/topBg.png") no-repeat scroll center;
+  width: 1020px;
+  height: 31px;
+}
+
+#content {
+  padding: 0px 20px 20px;
+  background: url("../images/contentbg.png") repeat-y scroll center;
+  width: 980px;
+  /*border: 1px solid #ccc;*/
+}
+
+#Header {
+  background: transparent url("../images/logo.png") no-repeat scroll center;
+  width: 980px;
+  height: 136px;
+}
+#HeaderDev {
+  background: transparent url("../images/logoDev.png") no-repeat scroll center;
+  width: 980px;
+  height: 136px;
+}
+#HeaderLink{
+  display: block;
+  width: 958px;
+  height: 136px;
+}
+
+/* Navigation plugin, top level. */
+#menu {
+    float: left;
+    /*border: 1px solid #ccc;*/
+}
+
+/* Application log textarea */
+#log {
+    width: 920px;
+    height: auto;
+}
+
+div.tabHeader {
+    padding: 5px 15px 0px 15px;
+}
+.tabHeader h1 {
+    color: #2647a0;
+    font-weight: bold;
+    font-size: 17px;
+    margin: 0 0 .3em 0;
+}
+.tabHeader h2 {
+    color: #2647a0;
+    font-weight: normal;
+    font-size: 15px;
+    margin: 0 0 .3em 0;
+}
+
+a:link, a:visited, a:hover {
+    color: #006dba;
+    font-weight: bold;
+    text-decoration: none;
+}
+
+img {
+    border: 0px;
+}
+
+/*Do not specify a global h2 and h3
+    Since this changes filterPane and other headers.*/
+h1 {
+    color: #006dba;
+    font-weight: normal;
+    font-size: 17px;
+    margin: 0 0 .3em 0;
+}
+
+ul {
+    padding-left: 15px;
+}
+
+input, select, textarea {
+    background-color: #fcfcfc;
+    border: 1px solid #ccc;
+    font: 14px verdana, arial, helvetica, sans-serif;
+    margin: 2px 0;
+    padding: 2px 4px;
+}
+select {
+   padding: 2px 2px 2px 0;
+}
+textarea {
+    width: 450px;
+    height: 150px;
+    vertical-align: top;
+}
+
+input:focus, select:focus, textarea:focus {
+    border: 1px solid #b2d1ff;
+}
+
+.body {
+    padding: 20px 20px 20px 20px;
+    text-align: center;
+    /*border: 1px solid #ccc;*/
+}
+
+/* Ask IE to behave. Margin, width and height might be ignored by some FF versions. */
+input[type="checkbox"] {
+    background: transparent;
+    border: 0;
+    margin-bottom: -1px;
+}
+input[type="radio"] {
+    background: transparent;
+    border: 0;
+    margin-bottom: -1px;
+}
+
+/* Logout and Top Navigation Level */
+
+.appControl {
+    height: 2em;
+}
+.appControl a {
+    color: #666;
+}
+
+.logoutButton {
+    float: right;
+    padding: 0.3em 0px 0.3em 0;
+    font-size: 14px;
+    margin: 0 50px 0 0;
+    /*border: 1px solid #ccc;*/
+}
+
+.logoutButton:hover {
+    color: red;
+    padding: 0.5em 0px 0.1em 0;
+}
+
+/* ORIGINAL NAVIGATION MENU */
+
+.nav {
+    text-align: center;
+    background: url("../images/linkPanel_long.png") top no-repeat;
+    padding: 10px 0px 0px 0px;
+    width: 980px;
+    height: 40px;
+}
+
+.menuButton {
+    font-size: 14px;
+    padding: 0 5px;
+}
+.menuButton a {
+    color: #333;
+    padding: 14px 25px;
+}
+.menuButton a.home {
+    /*background: url(../images/skin/house.png) center left no-repeat;*/
+    color: #333;
+    /*padding: 25px;*/
+}
+.menuButton a.list {
+    /*background: url(../images/skin/database_table.png) center left no-repeat;*/
+    color: #333;
+    /*padding-left: 25px;*/
+}
+.menuButton a.create {
+    /*background: url(../images/skin/database_add.png) center left no-repeat;*/
+    color: #333;
+    /*padding-left: 25px;*/
+}
+
+/* MESSAGES AND ERRORS */
+
+.jQueryAjaxLoading {
+    margin: 10px 0 5px 0;
+    padding: 5px 5px 5px 0px;
+}
+
+.message {
+    background: #f3f8fc url(../images/skin/information.png) 8px 50% no-repeat;
+    border: 1px solid #b2d1ff;
+    color: #006dba;
+    margin: 10px 0 5px 0;
+    padding: 5px 5px 5px 0px
+}
+
+.message_error {
+    background: #fff3f3 url(../images/skin/exclamation.png) 8px 50% no-repeat;
+    border: 1px solid red;
+    color: #cc0000;
+    margin: 10px 0 5px 0;
+    padding: 5px 5px 5px 0px
+}
+
+div.errors {
+    background: #fff3f3;
+    border: 1px solid red;
+    color: #cc0000;
+    margin: 10px 0 5px 0;
+    padding: 5px 0 5px 0;
+}
+div.errors ul {
+    list-style: none;
+    padding: 0;
+}
+div.errors li {
+    background: url(../images/skin/exclamation.png) 8px 0% no-repeat;
+    line-height: 16px;
+    padding-left: 30px;
+}
+
+td.errors select {
+    background: #ffEbEb; /*Set select background since select borders cannot be styled in IE*/
+    border: 1px solid red;
+}
+td.errors input {
+    border: 1px solid red;
+}
+td.errors textarea {
+    border: 1px solid red;
+}
+
+input.time {
+    width:40px;
+}
+input.time.errors {
+    border: 1px solid red;
+}
+input.medium {
+    width:60px;
+}
+input.medium.errors {
+    border: 1px solid red;
+}
+input.description {
+    width:450px;
+}
+
+/* TABLES */
+
+table {
+    border: 1px solid #ccc;
+    width: 100%;
+}
+tr {
+    border: 0;
+}
+td, th {
+    font: 14px verdana, arial, helvetica, sans-serif;
+    line-height: 17px;
+    padding: 5px 6px;
+    text-align: left;
+    vertical-align: top;
+}
+tr.total {
+    background: #EDEDED;
+}
+tr.total td{
+    color: #555;
+    font-size: 14px;
+    font-weight: bold;
+}
+td.idColumn {
+    width: 25px;
+}
+th {
+    background: #fff url(../images/skin/shadow.jpg);
+    color: #555;
+    font-size: 14px;
+    font-weight: bold;
+    line-height: 17px;
+    padding: 2px 6px;
+}
+th a:link, th a:visited, th a:hover {
+    color: #333;
+    display: block;
+    font-size: 14px;
+    text-decoration: none;
+    width: 100%;
+}
+th.asc a, th.desc a {
+    background-position: right;
+    background-repeat: no-repeat;
+}
+th.asc a {
+    background-image: url(../images/skin/sorted_asc.gif);
+}
+th.desc a {
+    background-image: url(../images/skin/sorted_desc.gif);
+}
+
+.odd {
+    background: #f7f7f7;
+}
+.even {
+    background: #fff;
+}
+
+.clickableOdd {
+    background: #f7f7f7;
+    cursor: pointer;
+}
+.clickableEven {
+    background: #fff;
+    cursor: pointer;
+}
+.clickableEven td.notClickable {
+    cursor: default;
+}
+.clickableOdd td.notClickable {
+    cursor: default;
+}
+
+/* LIST */
+
+div.list {
+    clear:both;
+}
+.list table {
+    border-collapse: collapse;
+}
+.list th, .list td {
+    border-left: 1px solid #ddd;
+}
+.list th:hover, .list tr:hover {
+    background: #b2d1ff;
+}
+
+/* PAGINATION */
+
+.paginateButtons {
+    border-top: 0;
+    color: #666;
+    font-size: 14px;
+    overflow: hidden;
+    padding: 10px 3px;
+}
+.paginateButtons a {
+    background: #fff url(../images/skin/shadow.jpg) bottom repeat-x;
+    border: 1px solid #ccc;
+    border-color: #ccc #aaa #aaa #ccc;
+    color: #666;
+    margin: 0 3px;
+    padding: 2px 6px;
+}
+.paginateButtons span {
+    padding: 2px 3px;
+}
+
+.searchButtons {
+    background: #fff url(../images/skin/shadow.jpg) bottom repeat-x;
+    border: 1px solid #ccc;
+    border-color: #ccc #aaa #aaa #ccc;
+    margin: 0 0.5em;
+}
+.searchButtons a {
+    background: transparent url(../images/skin/database_search.png)  5px 50% no-repeat;
+    padding-left: 28px;
+    border: none;
+    margin: 0;
+}
+
+/* DIALOG */
+
+.dialog table {
+    padding: 5px 0;
+}
+
+.prop {
+    padding: 5px;
+}
+.prop .name {
+    text-align: left;
+    width: 15%;
+    white-space: nowrap;
+}
+.prop .value {
+    text-align: left;
+    width: 85%;
+}
+.prop .groupHeader {
+    text-decoration:underline;
+    text-align: left;
+    width: 15%;
+    white-space: nowrap;
+}
+.prop .groupName {
+    text-indent:15px;
+    text-align: left;
+    width: 15%;
+    white-space: nowrap;
+}
+
+/* ACTION BUTTONS */
+.generalButton {
+    background: #fff url(../images/skin/shadow.jpg) bottom repeat-x;
+    color: #444;
+    font-size: 14px;
+    font-weight: bold;
+    cursor: pointer;
+    margin-left: 5px;
+    overflow: hidden;
+    padding: 0.1em 0.4em 0.1em 0.4em;
+}
+
+.buttons {
+    background: #fff url(../images/skin/shadow.jpg) bottom repeat-x;
+    border: 1px solid #ccc;
+    color: #666;
+    font-size: 14px;
+    margin-top: -1px;
+    margin-bottom: 5px;
+    overflow: hidden;
+    padding: 3px;
+}
+.buttons input {
+    background: #fff;
+    border: 0;
+    color: #333;
+    cursor: pointer;
+    font-size: 14px;
+    font-weight: bold;
+    margin-left: 3px;
+    overflow: visible;
+    padding: 0px 6px;
+}
+.buttons input.delete {
+    background: transparent url(../images/skin/database_delete.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.trash {
+    background: transparent url(../images/skin/bin_closed.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.restore {
+    background: transparent url(../images/skin/bin_empty.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.cancel {
+    background: transparent url(../images/skin/cross.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.complete {
+    background: transparent url(../images/skin/tick.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.flag {
+    background: transparent url(../images/skin/flag_red.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.reopen {
+    background: transparent url(../images/skin/door_open.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.approve {
+    background: transparent url(../images/skin/cog_add.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.renegeApproval {
+    background: transparent url(../images/skin/cog_delete.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.edit {
+    background: transparent url(../images/skin/database_edit.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.save {
+    background: transparent url(../images/skin/database_save.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.add {
+    background: transparent url(../images/skin/database_add.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.search {
+    background: transparent url(../images/skin/database_search.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.link {
+    background: transparent url(../images/skin/database_link.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.go {
+    background: transparent url(../images/skin/database_go.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+.buttons input.table {
+    background: transparent url(../images/skin/database_table.png) 5px 50% no-repeat;
+    padding-left: 28px;
+}
+
+#bottom {
+  background: url("../images/bottomBg.png") no-repeat scroll center;
+  width: 1020px;
+  height: 100px;
+}
+
+/* Text Search */
+div.textSearchWrapper {
+    float: left;
+    width: 100%;
+}
+
+div.textSearchInput {
+    float: left;
+    width: 500px;
+    margin: 0 0 0 220px;
+    padding: 0;
+}
+
+div.textSearchSelect {
+    text-align: left;
+    padding: 5px 5px 5px 15px;
+}
+
+div.textSearchRightFloat {
+    float: right;
+    text-align: right;
+    margin: 0 10px 0 0;
+}
+
+/* Overlay Pane and filterPane plugin*/
+div.overlayPane {
+    position: absolute;
+    width:70%;
+    left: 50%;
+    margin-left: -36%;
+    top: 50%;
+    margin-top: -26%;
+    border: 2px solid #666666;
+    background-color: white;
+    padding: 5px;
+    z-index: 0;
+}
+
+.overlayTable {
+    width: 100%;
+}
+
+a.remove img {
+    border:none;
+}
+
+ /* Navigation Plugin Override */
+.navigation {
+    padding: 0px 0px 0px 50px;
+    list-style-type: none;
+    clear: both;
+    font-size: 14px;
+    /*overflow: hidden;*/ /* Clearing floats */
+}
+
+.navigation li {
+    float: left;
+    /*border: 0px*/
+    /* border: 1px solid #888; */
+     /*border-left-color: #bbb;*/  /* Highlight border-color */
+}
+
+.navigation li.navigation_first {
+     /*border-left-color: #888; */
+}
+
+.navigation li.navigation_active {
+     /*border-left-color: #555;*/  /* Highlight border-color of active item */
+}
+
+.navigation li a {
+    color: #666;
+    /* background-color: #aaa; */
+    padding: 0.3em 0.75em 0;
+    display: block;
+    text-decoration: none;
+}
+
+.navigation li a:hover {
+    color: red;
+    /* background-color: #999; */
+/*     font-weight: normal; */
+/*     font-size: 14px; */
+    padding: 0.5em 0.75em;
+    /*cursor: default;*/
+}
+
+.navigation li.navigation_active a {
+    /* background-color: #555; */
+/*    color: #fff;*/
+    color: #006dba;
+    /*color: black;*/
+    font-weight: bold;
+    font-size: 17px;
+    margin: 0 0 0 0;
+    /*cursor: default;*/
+}
+
+.navigation li.navigation_active a:hover {
+    color: #006dba;
+    font-weight: bold;
+    font-size: 17px;
+    padding: 0.3em 0.75em;
+    /*background-color: #555;*/
+}
+
+/* Sub navigation */
+.subnavigation {
+    /*padding: 0px 0px 0px 165px;*/
+    padding: 0px 0px 0px 105px;
+    list-style-type: none;
+    clear: both;
+    overflow: hidden; /* Clearing floats */
+}
+.subnavigation li {
+    float: left;
+    /* background-color: #555; */
+    padding: 0em 0.75em;
+    border-width: 0px 0;
+}
+.subnavigation li a {
+    color: #006dba;
+    font-weight: bold;
+    font-size: 17px;
+    display: block;
+    /*padding: 0px 0;*/
+    /* border-color: #555; */
+    border-style: solid;
+    border-width: 0px 0;
+    text-decoration: none;
+    /*margin: 0 0 0 0;*/
+    /*cursor: default;*/
+}
+
+.subnavigation li a:visited {
+    color: #006dba;
+}
+
+.subnavigation li a:hover {
+    /*color: red;*/
+    /*border-color: black;*/ 
+    border-width: 1px 0;
+}
+.subnavigation li.subnavigation_active a {
+    /*color: #e0e0e0; */
+    /*cursor: default;*/
+    /*border-color: #e0e0e0;*/
+    border-width: 1px 0;
+}
+
+/* Tree */
+
+div.static_tree {
+}
+div.static_tree_compact {
+    height:10em;
+    width:100%;
+    overflow:auto;
+}
+div.static_tree ul {
+    list-style-type: none;
+    padding-left: 15px;
+}
+div.static_tree li {
+    background: url(../images/skin/ln.gif) 0px 0px no-repeat;
+    padding-left: 20px;
+    margin: 2px;
+}
+
+div.tree_button {
+    float: left;
+}
+div.tree_button a {
+}
+div.tree_button img {
+    padding: 0.3em 0.5em 0 0.3em;
+}
+div.tree_button img:hover {
+    padding: 0.5em 0.5em 0 0.3em;
+}
+
+div.tree {
+}
+div.tree li a{
+}
+div.tree ul {
+    list-style-type: none;
+    padding-left: 15px;
+}
+div.tree li {
+    background: url(../images/skin/ln.gif) 0px 0px no-repeat;
+    padding-left: 10px;
+    margin: 2px;
+}
+div.pane_close {
+    position: absolute;
+    right: 5px;
+    padding: 5px;
+    cursor: pointer;
+}
+
+/* CheckBoxList Tag Lib */
+
+.CheckBoxList {
+    height: 300px;
+    overflow: auto;
+    overflow-x: hidden;
+    width: 400px;
+    border: 1px solid #ccc;
+    list-style-type: none;
+    margin: 0;
+    padding: 0px;
+}
+.CheckBoxList li {
+    padding: 5px;
+}
Index: /branches/features/grailsUpgrade/web-app/css/tabviewCustom.css
===================================================================
--- /branches/features/grailsUpgrade/web-app/css/tabviewCustom.css	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/css/tabviewCustom.css	(revision 875)
@@ -0,0 +1,317 @@
+/*
+Copyright (c) 2008, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.6.0
+*/
+.yui-navset .yui-nav li,
+.yui-navset .yui-navset-top .yui-nav li,.yui-navset .yui-navset-bottom .yui-nav li{
+    margin:0 0.5em 0 0;
+}
+
+.yui-navset-left .yui-nav li,
+.yui-navset-right .yui-nav li{
+    margin:0 0 0.5em;
+}
+
+.yui-navset .yui-content .yui-hidden{
+    display:none;
+}
+
+.yui-navset .yui-navset-left .yui-nav,
+.yui-navset .yui-navset-right .yui-nav,
+.yui-navset-left .yui-nav,
+.yui-navset-right .yui-nav{
+    width:6em;
+}
+
+.yui-navset-top .yui-nav,
+.yui-navset-bottom .yui-nav{
+    width:auto;
+}
+
+.yui-navset .yui-navset-left,
+.yui-navset-left{
+    padding:0 0 0 6em;
+}
+
+.yui-navset-right{
+    padding:0 6em 0 0;
+}
+
+.yui-navset-top,.yui-navset-bottom{
+    padding:auto;
+}
+
+.yui-nav,
+.yui-nav li{
+    margin:0;
+    padding:0;
+    list-style:none;
+}
+
+.yui-navset li em{
+    font-style:normal;
+}
+
+.yui-navset{
+    position:relative;
+    zoom:1;
+}
+
+.yui-navset .yui-content{
+    zoom:1;
+}
+
+.yui-navset .yui-nav li,
+.yui-navset .yui-navset-top .yui-nav li,
+.yui-navset .yui-navset-bottom .yui-nav li{
+    display:inline-block;
+    display:-moz-inline-stack;
+    display:inline;
+    vertical-align:bottom;
+    cursor:pointer;zoom:1;
+}
+
+.yui-navset-left .yui-nav li,
+.yui-navset-right .yui-nav li{
+    display:block;
+}
+
+.yui-navset .yui-nav a{
+    position:relative;
+}
+
+.yui-navset .yui-nav li a,
+.yui-navset-top .yui-nav li a,
+.yui-navset-bottom .yui-nav li a{
+    display:block;
+    display:inline-block;
+    vertical-align:bottom;
+    zoom:1;
+}
+
+.yui-navset-left .yui-nav li a,
+.yui-navset-right .yui-nav li a{
+    display:block;
+}
+
+.yui-navset-bottom .yui-nav li a{
+    vertical-align:text-top;
+}
+
+.yui-navset .yui-nav li a em,
+.yui-navset-top .yui-nav li a em,
+.yui-navset-bottom .yui-nav li a em{
+    display:block;
+}
+
+.yui-navset .yui-navset-left .yui-nav,
+.yui-navset .yui-navset-right .yui-nav,
+.yui-navset-left .yui-nav,
+.yui-navset-right .yui-nav{
+    position:absolute;
+    z-index:1;
+}
+
+.yui-navset-top .yui-nav,
+.yui-navset-bottom .yui-nav{
+    position:static;
+}
+
+.yui-navset .yui-navset-left .yui-nav,
+.yui-navset-left .yui-nav{
+    left:0;
+    right:auto;
+}
+
+.yui-navset .yui-navset-right .yui-nav,
+.yui-navset-right .yui-nav{
+    right:0;
+    left:auto;
+}
+
+.yui-skin-sam .yui-navset .yui-nav,
+.yui-skin-sam .yui-navset .yui-navset-top .yui-nav{/*Nav underl line*/
+    border:solid #2647a0;
+    border-width:0 0 5px;
+    Xposition:relative;
+    zoom:1;
+}
+
+.yui-skin-sam .yui-navset .yui-nav li,
+.yui-skin-sam .yui-navset .yui-navset-top .yui-nav li{
+    margin:0 0.16em 0 0;
+    padding:1px 0 0;
+    zoom:1;
+}
+
+.yui-skin-sam .yui-navset .yui-nav .selected,
+.yui-skin-sam .yui-navset .yui-navset-top .yui-nav .selected{
+    margin:0 0.16em -1px 0;
+}
+
+.yui-skin-sam .yui-navset .yui-nav a,
+.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a{/* tab background */
+/*    background:#d8d8d8 url("../images/skin/sprite.png") repeat-x; */
+    background:#d8d8d8;
+    border:solid #a3a3a3;
+    border-width:0 1px;
+    color:#000;
+    position:relative;
+    text-decoration:none;
+}
+
+.yui-skin-sam .yui-navset .yui-nav a em,
+.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a em{
+    border:solid #a3a3a3;
+    border-width:1px 0 0;
+    cursor:hand;
+    padding:0.25em .75em;
+    left:0;
+    right:0;
+    bottom:0;
+    top:-1px;
+    position:relative;
+}
+
+.yui-skin-sam .yui-navset .yui-nav .selected a,
+.yui-skin-sam .yui-navset .yui-nav .selected a:focus,
+.yui-skin-sam .yui-navset .yui-nav .selected a:hover{/*selected tab background*/
+/*     background:#2647a0 url("../images/skin/sprite.png") repeat-x left -1400px;  */
+    background:#2647a0;
+    color:#fff;
+}
+
+.yui-skin-sam .yui-navset .yui-nav a:hover,
+.yui-skin-sam .yui-navset .yui-nav a:focus{/*hover background*/
+/*     background:#bfdaff url("../images/skin/sprite.png") repeat-x left -1300px;  */
+    background:#bfdaff;
+    outline:0;
+}
+
+.yui-skin-sam .yui-navset .yui-nav .selected a em{
+    padding:0.35em 0.75em;
+}
+
+.yui-skin-sam .yui-navset .yui-nav .selected a,
+.yui-skin-sam .yui-navset .yui-nav .selected a em{
+    border-color:#243356;
+}
+
+.yui-skin-sam .yui-navset .yui-content{/* content background color */
+    background: #FFFFE1;
+/*   background: url("../images/Contentbg.png") repeat-y scroll center; */
+}
+
+.yui-skin-sam .yui-navset .yui-content,
+.yui-skin-sam .yui-navset .yui-navset-top .yui-content{
+    border:0px solid #808080;
+    border-top-color:#243356;
+    padding:0.25em 0.5em;
+}
+
+.yui-skin-sam .yui-navset-left .yui-nav,
+.yui-skin-sam .yui-navset .yui-navset-left .yui-nav,
+.yui-skin-sam .yui-navset .yui-navset-right .yui-nav,
+.yui-skin-sam .yui-navset-right .yui-nav{
+    border-width:0 5px 0 0;
+    Xposition:absolute;
+    top:0;
+    bottom:0;
+}
+
+.yui-skin-sam .yui-navset .yui-navset-right .yui-nav,
+.yui-skin-sam .yui-navset-right .yui-nav{
+    border-width:0 0 0 5px;
+}
+
+.yui-skin-sam .yui-navset-left .yui-nav li,
+.yui-skin-sam .yui-navset .yui-navset-left .yui-nav li,
+.yui-skin-sam .yui-navset-right .yui-nav li{
+    margin:0 0 0.16em;
+    padding:0 0 0 1px;
+}
+
+.yui-skin-sam .yui-navset-right .yui-nav li{
+    padding:0 1px 0 0;
+}
+
+.yui-skin-sam .yui-navset-left .yui-nav .selected,
+.yui-skin-sam .yui-navset .yui-navset-left .yui-nav .selected{
+    margin:0 -1px 0.16em 0;
+}
+
+.yui-skin-sam .yui-navset-right .yui-nav .selected{
+    margin:0 0 0.16em -1px;
+}
+
+.yui-skin-sam .yui-navset-left .yui-nav a,
+.yui-skin-sam .yui-navset-right .yui-nav a{
+    border-width:1px 0;
+}
+
+.yui-skin-sam .yui-navset-left .yui-nav a em,
+.yui-skin-sam .yui-navset .yui-navset-left .yui-nav a em,
+.yui-skin-sam .yui-navset-right .yui-nav a em{
+    border-width:0 0 0 1px;
+    padding:0.2em .75em;
+    top:auto;
+    left:-1px;
+}
+
+.yui-skin-sam .yui-navset-right .yui-nav a em{
+    border-width:0 1px 0 0;
+    left:auto;
+    right:-1px;
+}
+
+.yui-skin-sam .yui-navset-left .yui-nav a,
+.yui-skin-sam .yui-navset-left .yui-nav .selected a,
+.yui-skin-sam .yui-navset-left .yui-nav a:hover,
+.yui-skin-sam .yui-navset-right .yui-nav a,
+.yui-skin-sam .yui-navset-right .yui-nav .selected a,
+.yui-skin-sam .yui-navset-right .yui-nav a:hover,
+.yui-skin-sam .yui-navset-bottom .yui-nav a,
+.yui-skin-sam .yui-navset-bottom .yui-nav .selected a,
+.yui-skin-sam .yui-navset-bottom .yui-nav a:hover{
+    background-image:none;
+}
+
+.yui-skin-sam .yui-navset-left .yui-content{
+    border:1px solid #808080;
+    border-left-color:#243356;
+}
+
+.yui-skin-sam .yui-navset-bottom .yui-nav,
+.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav{
+    border-width:5px 0 0;
+}
+
+.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav .selected,
+.yui-skin-sam .yui-navset-bottom .yui-nav .selected{
+    margin:-1px 0.16em 0 0;
+}
+
+.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav li,
+.yui-skin-sam .yui-navset-bottom .yui-nav li{
+    padding:0 0 1px 0;
+    vertical-align:top;
+}
+
+.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav li a,
+.yui-skin-sam .yui-navset-bottom .yui-nav li a{
+}
+
+.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav a em,
+.yui-skin-sam .yui-navset-bottom .yui-nav a em{
+    border-width:0 0 1px;
+    top:auto;
+    bottom:-1px;
+}
+
+.yui-skin-sam .yui-navset-bottom .yui-content,
+.yui-skin-sam .yui-navset .yui-navset-bottom .yui-content{
+    border:1px solid #808080;
+    border-bottom-color:#243356;
+}
Index: /branches/features/grailsUpgrade/web-app/js/application.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/application.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/application.js	(revision 875)
@@ -0,0 +1,70 @@
+var Ajax;
+if (Ajax && (Ajax != null)) {
+    Ajax.Responders.register({
+    onCreate: function() {
+        if($('spinner') && Ajax.activeRequestCount>0)
+        Effect.Appear('spinner',{duration:0.5,queue:'end'});
+    },
+    onComplete: function() {
+        if($('spinner') && Ajax.activeRequestCount==0)
+        Effect.Fade('spinner',{duration:0.5,queue:'end'});
+    }
+    });
+}
+
+// jQuery AJAX utils.
+
+function loadingIndication() {
+    return jQuery('#jQueryAjaxLoading').clone();
+}
+
+function errorIndication(jqXHR, textStatus, errorThrown) {
+    return jQuery('#jQueryAjaxDefaultError').clone().append('Status:'+jqXHR.status+', '+textStatus+'.');
+}
+
+// Apply updates to multiple page elements.
+// @json JSON response object from an ajax request.
+// @json.updates Array of element updates to apply.
+// @element.mode The update mode: execute or replace, prepend, append.
+// @element.script Script to execute, if execute mode.
+// @element.target jQuery target selector, if update mode.
+// @element.content Content to update target with, if update mode.
+function applyElementUpdates(json) {
+    var updates;
+    var script;
+
+    if(json.updates) {
+        updates = json.updates;
+        var element;
+        var scripts = new Array();
+
+        for(element in updates) {
+            element = updates[element];
+
+            switch(element.mode) {
+                case 'execute':
+                    scripts.push(element.script);
+                    break;
+                case 'replace':
+                    jQuery(element.target).html(element.content);
+                    break;
+                case 'prepend':
+                    jQuery(element.target).prepend(element.content);
+                    break;
+                case 'append':
+                    jQuery(element.target).append(element.content);
+                    break;
+            }
+        }
+
+        // Run scripts.
+        for(script in scripts) {
+            script = scripts[script];
+            eval(script);
+        }
+
+    } // if(json.updates)
+} // applyElementUpdates
+
+
+
Index: /branches/features/grailsUpgrade/web-app/js/assetTree.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/assetTree.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/assetTree.js	(revision 875)
@@ -0,0 +1,34 @@
+
+function showAssetTreePane(paneDivId, loadingImg, url) {
+
+    Effect.Appear(paneDivId,{duration:0.4});
+
+    // Disabled since pulsing effect blocks other javascript till complete.
+    // The effect may be stopped with e.cancel() but we will use the default Grails spinner for now.
+    // def e = new Effect.Pulsate($(loadingImg), { pulses: 200, duration: 133 });
+
+    new Ajax.Updater({ success: paneDivId }, url, {asynchronous:true,evalScripts:true});
+}
+
+function hideAssetTreePane(paneDivId, tableDivId, saveUrl) {
+
+    // Collect the visible branch div's first.
+    var visibleDivs = $(tableDivId).select('div').findAll(function(el) { return el.visible(); })
+    var params = "assetTreeVisibleBranches=";
+
+    // Hide the pane.
+    $(paneDivId).toggle();
+
+    // Add the id of each visible div to params.
+    visibleDivs.each(function(it) {
+        params += it.identify();
+        params += ","
+    });
+
+    // Remove the trailing comma.
+    params = params.slice(0,params.length-1);
+
+    // Post the id's of all visible branch div's.
+    // asynchronous: false is against the prototype recommendations but appears to be needed in this case.
+    new Ajax.Request(saveUrl, {parameters: params, asynchronous: false});
+}
Index: /branches/features/grailsUpgrade/web-app/js/dynamicOneToMany.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/dynamicOneToMany.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/dynamicOneToMany.js	(revision 875)
@@ -0,0 +1,29 @@
+
+// Depends on jQuery.
+
+// Add a child by cloning a template and appending to wrapper element.
+// Used with a parent and LazyList of children (One-to-Many).
+// Since javascript has no pointers the childCount source var must be incremented by the calling code.
+// @param wrapperId The id of the wrapper element, e.g: div or tbody.
+// @param cloneId The id of the element to clone.
+// @param lazyList The name of the LazyList.
+// @param fields A list of fields in the clone that need name and id set.
+// @param focusField Which field in the fields list to focus on after adding.
+// @param childCount The current child count, used to set LazyList index, remember to increment!
+function addChild(wrapperId, cloneId, lazyList, fields, focusField, childCount){
+
+    var clone = jQuery("#"+cloneId).clone();
+    clone.attr('id', lazyList+childCount);
+    var htmlId = lazyList+'['+childCount+'].';
+
+    var fieldsMap = {};
+    jQuery.each(fields, function(index, field) {
+        fieldsMap[field] = clone.find('[id$="'+field+'"]');
+        fieldsMap[field].attr('id',htmlId + field)
+                                    .attr('name',htmlId + field);
+    });
+
+    jQuery("#"+wrapperId).append(clone);
+    clone.show();
+    fieldsMap[focusField].focus();
+}
Index: /branches/features/grailsUpgrade/web-app/js/jquery.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/jquery.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/jquery.js	(revision 875)
@@ -0,0 +1,16 @@
+/*!
+ * jQuery JavaScript Library v1.5.1
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Wed Feb 23 13:55:29 2011 -0500
+ */
+(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==="string"&&(f[h.toLowerCase()]=a.converters[h]);l=k,k=e[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=f[m]||f["* "+k];if(!n){p=b;for(o in f){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=f[j[1]+" "+k];if(p){o=f[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&d.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bP(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bO(a,b,c,e){if(d.isArray(b)&&b.length)d.each(b,function(b,f){c||bq.test(a)?e(a,f):bO(a+"["+(typeof f==="object"||d.isArray(f)?b:"")+"]",f,c,e)});else if(c||b==null||typeof b!=="object")e(a,b);else if(d.isArray(b)||d.isEmptyObject(b))e(a,"");else for(var f in b)bO(a+"["+f+"]",b[f],c,e)}function bN(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bH,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bN(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bN(a,c,d,e,"*",g));return l}function bM(a){return function(b,c){typeof b!=="string"&&(c=b,b="*");if(d.isFunction(c)){var e=b.toLowerCase().split(bB),f=0,g=e.length,h,i,j;for(;f<g;f++)h=e[f],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bo(a,b,c){var e=b==="width"?bi:bj,f=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return f;d.each(e,function(){c||(f-=parseFloat(d.css(a,"padding"+this))||0),c==="margin"?f+=parseFloat(d.css(a,"margin"+this))||0:f-=parseFloat(d.css(a,"border"+this+"Width"))||0});return f}function ba(a,b){b.src?d.ajax({url:b.src,async:!1,dataType:"script"}):d.globalEval(b.text||b.textContent||b.innerHTML||""),b.parentNode&&b.parentNode.removeChild(b)}function _(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function $(a,b){if(b.nodeType===1){var c=b.nodeName.toLowerCase();b.clearAttributes(),b.mergeAttributes(a);if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(d.expando)}}function Z(a,b){if(b.nodeType===1&&d.hasData(a)){var c=d.expando,e=d.data(a),f=d.data(b,e);if(e=e[c]){var g=e.events;f=f[c]=d.extend({},e);if(g){delete f.handle,f.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)d.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function Y(a,b){return d.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function O(a,b,c){if(d.isFunction(b))return d.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return d.grep(a,function(a,d){return a===b===c});if(typeof b==="string"){var e=d.grep(a,function(a){return a.nodeType===1});if(J.test(b))return d.filter(b,e,!c);b=d.filter(b,e)}return d.grep(a,function(a,e){return d.inArray(a,b)>=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;i<t.length;i++)g=t[i],g.origType.replace(p,"")===a.type?r.push(g.selector):t.splice(i--,1);f=d(a.target).closest(r,a.currentTarget);for(j=0,k=f.length;j<k;j++){m=f[j];for(i=0;i<t.length;i++){g=t[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,e=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,e=d(a.relatedTarget).closest(g.selector)[0];(!e||e!==h)&&q.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=q.length;j<k;j++){f=q[j];if(c&&f.level>c)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function w(){return!0}function v(){return!1}function g(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return E.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){e=i[c],f=a[c];if(i===f)continue;l&&f&&(d.isPlainObject(f)||(g=d.isArray(f)))?(g?(g=!1,h=e&&d.isArray(e)?e:[]):h=e&&d.isPlainObject(e)?e:{},i[c]=d.extend(l,h,f)):f!==b&&(i[c]=f)}return i},d.extend({noConflict:function(b){a.$=f,b&&(a.jQuery=e);return d},isReady:!1,readyWait:1,ready:function(a){a===!0&&d.readyWait--;if(!d.readyWait||a!==!0&&!d.isReady){if(!c.body)return setTimeout(d.ready,1);d.isReady=!0;if(a!==!0&&--d.readyWait>0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g<h;)if(c.apply(a[g++],e)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(var j=a[0];g<h&&c.call(j,g,j)!==!1;j=a[++g]){}return a},trim:F?function(a){return a==null?"":F.call(a)}:function(a){return a==null?"":(a+"").replace(j,"").replace(k,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var e=d.type(a);a.length==null||e==="string"||e==="function"||e==="regexp"||d.isWindow(a)?D.call(c,a):d.merge(c,a)}return c},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,b,c){var d=[],e;for(var f=0,g=a.length;f<g;f++)e=b(a[f],f,c),e!=null&&(d[d.length]=e);return d.concat.apply([],d)},guid:1,proxy:function(a,c,e){arguments.length===2&&(typeof c==="string"?(e=a,a=e[c],c=b):c&&!d.isFunction(c)&&(e=c,c=b)),!c&&a&&(c=function(){return a.apply(e||this,arguments)}),a&&(c.guid=a.guid=a.guid||c.guid||d.guid++);return c},access:function(a,c,e,f,g,h){var i=a.length;if(typeof c==="object"){for(var j in c)d.access(a,j,c[j],f,g,e);return a}if(e!==b){f=!h&&f&&d.isFunction(e);for(var k=0;k<i;k++)g(a[k],c,f?e.call(a[k],k,g(a[k],c)):e,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},_Deferred:function(){var a=[],b,c,e,f={done:function(){if(!e){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=d.type(i),j==="array"?f.done.apply(f,i):j==="function"&&a.push(i);k&&f.resolveWith(k[0],k[1])}return this},resolveWith:function(d,f){if(!e&&!b&&!c){c=1;try{while(a[0])a.shift().apply(d,f)}catch(g){throw g}finally{b=[d,f],c=0}}return this},resolve:function(){f.resolveWith(d.isFunction(this.promise)?this.promise():this,arguments);return this},isResolved:function(){return c||b},cancel:function(){e=1,a=[];return this}};return f},Deferred:function(a){var b=d._Deferred(),c=d._Deferred(),e;d.extend(b,{then:function(a,c){b.done(a).fail(c);return this},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,promise:function(a){if(a==null){if(e)return e;e=a={}}var c=z.length;while(c--)a[z[c]]=b[z[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){var b=arguments.length,c=b<=1&&a&&d.isFunction(a.promise)?a:d.Deferred(),e=c.promise();if(b>1){var f=E.call(arguments,0),g=b,h=function(a){return function(b){f[a]=arguments.length>1?E.call(arguments,0):b,--g||c.resolveWith(e,f)}};while(b--)a=f[b],a&&d.isFunction(a.promise)?a.promise().then(h(b),c.reject):--g;g||c.resolveWith(e,f)}else c!==a&&c.resolve(a);return e},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test("Â ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e),b=e=f=null}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!g(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,h=b.nodeType,i=h?d.cache:b,j=h?b[d.expando]:d.expando;if(!i[j])return;if(c){var k=e?i[j][f]:i[j];if(k){delete k[c];if(!g(k))return}}if(e){delete i[j][f];if(!g(i[j]))return}var l=i[j][f];d.support.deleteExpando||i!=a?delete i[j]:i[j]=null,l?(i[j]={},h||(i[j].toJSON=d.noop),i[j][f]=l):h&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i<j;i++)h=g[i].name,h.indexOf("data-")===0&&(h=h.substr(5),f(this[0],h,e[h]))}}return e}if(typeof a==="object")return this.each(function(){d.data(this,a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(c===b){e=this.triggerHandler("getData"+k[1]+"!",[k[0]]),e===b&&this.length&&(e=d.data(this[0],a),e=f(this[0],a,e));return e===b&&k[1]?this.data(k[0]):e}return this.each(function(){var b=d(this),e=[k[0],c];b.triggerHandler("setData"+k[1]+"!",e),d.data(this,a,c),b.triggerHandler("changeData"+k[1]+"!",e)})},removeData:function(a){return this.each(function(){d.removeData(this,a)})}}),d.extend({queue:function(a,b,c){if(a){b=(b||"fx")+"queue";var e=d._data(a,b);if(!c)return e||[];!e||d.isArray(c)?e=d._data(a,b,d.makeArray(c)):e.push(c);return e}},dequeue:function(a,b){b=b||"fx";var c=d.queue(a,b),e=c.shift();e==="inprogress"&&(e=c.shift()),e&&(b==="fx"&&c.unshift("inprogress"),e.call(a,function(){d.dequeue(a,b)})),c.length||d.removeData(a,b+"queue",!0)}}),d.fn.extend({queue:function(a,c){typeof a!=="string"&&(c=a,a="fx");if(c===b)return d.queue(this[0],a);return this.each(function(b){var e=d.queue(this,a,c);a==="fx"&&e[0]!=="inprogress"&&d.dequeue(this,a)})},dequeue:function(a){return this.each(function(){d.dequeue(this,a)})},delay:function(a,b){a=d.fx?d.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){d.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var h=/[\n\t\r]/g,i=/\s+/,j=/\r/g,k=/^(?:href|src|style)$/,l=/^(?:button|input)$/i,m=/^(?:button|input|object|select|textarea)$/i,n=/^a(?:rea)?$/i,o=/^(?:radio|checkbox)$/i;d.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"},d.fn.extend({attr:function(a,b){return d.access(this,a,b,!0,d.attr)},removeAttr:function(a,b){return this.each(function(){d.attr(this,a,""),this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.addClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"){var b=(a||"").split(i);for(var c=0,e=this.length;c<e;c++){var f=this[c];if(f.nodeType===1)if(f.className){var g=" "+f.className+" ",h=f.className;for(var j=0,k=b.length;j<k;j++)g.indexOf(" "+b[j]+" ")<0&&(h+=" "+b[j]);f.className=d.trim(h)}else f.className=a}}return this},removeClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.removeClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"||a===b){var c=(a||"").split(i);for(var e=0,f=this.length;e<f;e++){var g=this[e];if(g.nodeType===1&&g.className)if(a){var j=(" "+g.className+" ").replace(h," ");for(var k=0,l=c.length;k<l;k++)j=j.replace(" "+c[k]+" "," ");g.className=d.trim(j)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,e=typeof b==="boolean";if(d.isFunction(a))return this.each(function(c){var e=d(this);e.toggleClass(a.call(this,c,e.attr("class"),b),b)});return this.each(function(){if(c==="string"){var f,g=0,h=d(this),j=b,k=a.split(i);while(f=k[g++])j=e?j:!h.hasClass(f),h[j?"addClass":"removeClass"](f)}else if(c==="undefined"||c==="boolean")this.className&&d._data(this,"__className__",this.className),this.className=this.className||a===!1?"":d._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(h," ").indexOf(b)>-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var k=i?f:0,l=i?f+1:h.length;k<l;k++){var m=h[k];if(m.selected&&(d.support.optDisabled?!m.disabled:m.getAttribute("disabled")===null)&&(!m.parentNode.disabled||!d.nodeName(m.parentNode,"optgroup"))){a=d(m).val();if(i)return a;g.push(a)}}if(i&&!g.length&&h.length)return d(h[f]).val();return g}if(o.test(c.type)&&!d.support.checkOn)return c.getAttribute("value")===null?"on":c.value;return(c.value||"").replace(j,"")}return b}var n=d.isFunction(a);return this.each(function(b){var c=d(this),e=a;if(this.nodeType===1){n&&(e=a.call(this,b,c.val())),e==null?e="":typeof e==="number"?e+="":d.isArray(e)&&(e=d.map(e,function(a){return a==null?"":a+""}));if(d.isArray(e)&&o.test(this.type))this.checked=d.inArray(c.val(),e)>=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=k.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&l.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:m.test(a.nodeName)||n.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var p=/\.(.*)$/,q=/^(?:textarea|input|select)$/i,r=/\./g,s=/ /g,t=/[^\w\s.|`]/g,u=function(a){return a.replace(t,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=v;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),u).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))d.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=d.event.special[h]||{};for(j=f||0;j<p.length;j++){q=p[j];if(e.guid===q.guid){if(l||n.test(q.namespace))f==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(f!=null)break}}if(p.length===0||f!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&d.removeEvent(a,h,s.handle),g=null,delete t[h]}if(d.isEmptyObject(t)){var w=s.handle;w&&(w.elem=null),delete s.events,delete s.handle,d.isEmptyObject(s)&&d.removeData(a,b,!0)}}},trigger:function(a,c,e){var f=a.type||a,g=arguments[3];if(!g){a=typeof a==="object"?a[d.expando]?a:d.extend(d.Event(f),a):d.Event(f),f.indexOf("!")>=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(p,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l<m;l++){var n=f[l];if(e||h.test(n.namespace)){c.handler=n.handler,c.data=n.data,c.handleObj=n;var o=n.handler.apply(this,k);o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[d.expando])return a;var e=a;a=d.Event(e);for(var f=this.props.length,g;f;)g=this.props[--f],a[g]=e[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=c.documentElement,i=c.body;a.pageX=a.clientX+(h&&h.scrollLeft||i&&i.scrollLeft||0)-(h&&h.clientLeft||i&&i.clientLeft||0),a.pageY=a.clientY+(h&&h.scrollTop||i&&i.scrollTop||0)-(h&&h.clientTop||i&&i.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:d.proxy,special:{ready:{setup:d.bindReady,teardown:d.noop},live:{add:function(a){d.event.add(this,F(a.origType,a.selector),d.extend({},a,{handler:E,guid:a.handler.guid}))},remove:function(a){d.event.remove(this,F(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){d.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},d.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},d.Event=function(a){if(!this.preventDefault)return new d.Event(a);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?w:v):this.type=a,this.timeStamp=d.now(),this[d.expando]=!0},d.Event.prototype={preventDefault:function(){this.isDefaultPrevented=w;var a=this.originalEvent;a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=w;var a=this.originalEvent;a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=w,this.stopPropagation()},isDefaultPrevented:v,isPropagationStopped:v,isImmediatePropagationStopped:v};var x=function(a){var b=a.relatedTarget;try{if(b!==c&&!b.parentNode)return;while(b&&b!==this)b=b.parentNode;b!==this&&(a.type=a.data,d.event.handle.apply(this,arguments))}catch(e){}},y=function(a){a.type=a.data,d.event.handle.apply(this,arguments)};d.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){d.event.special[a]={setup:function(c){d.event.add(this,b,c&&c.selector?y:x,a)},teardown:function(a){d.event.remove(this,b,a&&a.selector?y:x)}}}),d.support.submitBubbles||(d.event.special.submit={setup:function(a,b){if(this.nodeName&&this.nodeName.toLowerCase()!=="form")d.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&d(b).closest("form").length&&C("submit",this,arguments)}),d.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&d(b).closest("form").length&&a.keyCode===13&&C("submit",this,arguments)});else return!1},teardown:function(a){d.event.remove(this,".specialSubmit")}});if(!d.support.changeBubbles){var z,A=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(q.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return q.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return q.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i<j;i++)d.event.add(this[i],a,h,e);return this}}),d.fn.extend({unbind:function(a,b){if(typeof a!=="object"||a.preventDefault)for(var e=0,f=this.length;e<f;e++)d.event.remove(this[e],a,b);else for(var c in a)this.unbind(c,a[c]);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){d.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var c=d.Event(a);c.preventDefault(),c.stopPropagation(),d.event.trigger(c,b,this[0]);return c.result}},toggle:function(a){var b=arguments,c=1;while(c<b.length)d.proxy(a,b[c++]);return this.click(d.proxy(a,function(e){var f=(d._data(this,"lastToggle"+a.guid)||0)%c;d._data(this,"lastToggle"+a.guid,f+1),e.preventDefault();return b[f].apply(this,arguments)||!1}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var D={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};d.each(["live","die"],function(a,c){d.fn[c]=function(a,e,f,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:d(this.context);if(typeof a==="object"&&!a.preventDefault){for(var o in a)n[c](o,e,a[o],m);return this}d.isFunction(e)&&(f=e,e=b),a=(a||"").split(" ");while((h=a[i++])!=null){j=p.exec(h),k="",j&&(k=j[0],h=h.replace(p,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,h==="focus"||h==="blur"?(a.push(D[h]+k),h=h+k):h=(D[h]||h)+k;if(c==="live")for(var q=0,r=n.length;q<r;q++)d.event.add(n[q],"live."+F(h,m),{data:e,selector:m,handler:f,origType:h,origHandler:f,preType:l});else n.unbind("live."+F(h,m),f)}return this}}),d.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){d.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!=="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!=="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(f){if(f===!0)continue}else g=o=!0}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b==="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1){}a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(a===b){g=!0;return 0}if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(d||!l.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return k(c,null,null,[a]).length>0})}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};d.find=k,d.expr=k.selectors,d.expr[":"]=d.expr.filters,d.unique=k.uniqueSort,d.text=k.getText,d.isXMLDoc=k.isXML,d.contains=k.contains}();var G=/Until$/,H=/^(?:parents|prevUntil|prevAll)/,I=/,/,J=/^.[^:#\[\.,]*$/,K=Array.prototype.slice,L=d.expr.match.POS,M={children:!0,contents:!0,next:!0,prev:!0};d.fn.extend({find:function(a){var b=this.pushStack("","find",a),c=0;for(var e=0,f=this.length;e<f;e++){c=b.length,d.find(a,this[e],b);if(e>0)for(var g=c;g<b.length;g++)for(var h=0;h<c;h++)if(b[h]===b[g]){b.splice(g--,1);break}}return b},has:function(a){var b=d(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(d.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(O(this,a,!1),"not",a)},filter:function(a){return this.pushStack(O(this,a,!0),"filter",a)},is:function(a){return!!a&&d.filter(a,this).length>0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e<f;e++)i=a[e],j[i]||(j[i]=d.expr.match.POS.test(i)?d(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e<f;e++){g=this[e];while(g){if(l?l.index(g)>-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/<tbody/i,U=/<|&#?\w+;/,V=/<(?:script|object|embed|option|style)/i,W=/checked\s*(?:[^=]|=\s*.checked.)/i,X={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div<div>","</div>"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1></$2>");try{for(var c=0,e=this.length;c<e;c++)this[c].nodeType===1&&(d.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(f){this.empty().append(a)}}return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(d.isFunction(a))return this.each(function(b){var c=d(this),e=c.html();c.replaceWith(a.call(this,b,e))});typeof a!=="string"&&(a=d(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;d(this).remove(),b?d(b).before(a):d(c).append(a)})}return this.pushStack(d(d.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,e){var f,g,h,i,j=a[0],k=[];if(!d.support.checkClone&&arguments.length===3&&typeof j==="string"&&W.test(j))return this.each(function(){d(this).domManip(a,c,e,!0)});if(d.isFunction(j))return this.each(function(f){var g=d(this);a[0]=j.call(this,f,c?g.html():b),g.domManip(a,c,e)});if(this[0]){i=j&&j.parentNode,d.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?f={fragment:i}:f=d.buildFragment(a,this,k),h=f.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&d.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)e.call(c?Y(this[l],g):this[l],f.cacheable||m>1&&l<n?d.clone(h,!0,!0):h)}k.length&&d.each(k,ba)}return this}}),d.buildFragment=function(a,b,e){var f,g,h,i=b&&b[0]?b[0].ownerDocument||b[0]:c;a.length===1&&typeof a[0]==="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!V.test(a[0])&&(d.support.checkClone||!W.test(a[0]))&&(g=!0,h=d.fragments[a[0]],h&&(h!==1&&(f=h))),f||(f=i.createDocumentFragment(),d.clean(a,i,f,e)),g&&(d.fragments[a[0]]=h?f:1);return{fragment:f,cacheable:g}},d.fragments={},d.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){d.fn[a]=function(c){var e=[],f=d(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&f.length===1){f[b](this[0]);return this}for(var h=0,i=f.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){$(a,e),f=_(a),g=_(e);for(h=0;f[h];++h)$(f[h],g[h])}if(b){Z(a,e);if(c){f=_(a),g=_(e);for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1></$2>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]==="<table>"&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bb=/alpha\([^)]*\)/i,bc=/opacity=([^)]*)/,bd=/-([a-z])/ig,be=/([A-Z])/g,bf=/^-?\d+(?:px)?$/i,bg=/^-?\d/,bh={position:"absolute",visibility:"hidden",display:"block"},bi=["Left","Right"],bj=["Top","Bottom"],bk,bl,bm,bn=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bk(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bk)return bk(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bd,bn)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bo(a,b,e):d.swap(a,bh,function(){f=bo(a,b,e)});if(f<=0){f=bk(a,b,b),f==="0px"&&bm&&(f=bm(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bf.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bb.test(f)?f.replace(bb,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bl=function(a,c,e){var f,g,h;e=e.replace(be,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bm=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bf.test(d)&&bg.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bk=bl||bm,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bp=/%20/g,bq=/\[\]$/,br=/\r?\n/g,bs=/#.*$/,bt=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bu=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bv=/(?:^file|^widget|\-extension):$/,bw=/^(?:GET|HEAD)$/,bx=/^\/\//,by=/\?/,bz=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bA=/^(?:select|textarea)/i,bB=/\s+/,bC=/([?&])_=[^&]*/,bD=/(^|\-)([a-z])/g,bE=function(a,b,c){return b+c.toUpperCase()},bF=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,bG=d.fn.load,bH={},bI={},bJ,bK;try{bJ=c.location.href}catch(bL){bJ=c.createElement("a"),bJ.href="",bJ=bJ.href}bK=bF.exec(bJ.toLowerCase()),d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bG)return bG.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("<div>").append(c.replace(bz,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bA.test(this.nodeName)||bu.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(br,"\r\n")}}):{name:b.name,value:c.replace(br,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bJ,isLocal:bv.test(bK[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bM(bH),ajaxTransport:bM(bI),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bP(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bQ(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bD,bE)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bt.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bs,"").replace(bx,bK[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bB),e.crossDomain||(q=bF.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bK[1]||q[2]!=bK[2]||(q[3]||(q[1]==="http:"?80:443))!=(bK[3]||(bK[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bN(bH,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!bw.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(by.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bC,"$1_="+w);e.url=x+(x===e.url?(by.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bN(bI,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bO(g,a[g],c,f);return e.join("&").replace(bp,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bR=d.now(),bS=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bR++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bS.test(b.url)||f&&bS.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bS,l),b.url===j&&(f&&(k=k.replace(bS,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bT=d.now(),bU,bV;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bX()||bY()}:bX,bV=d.ajaxSettings.xhr(),d.support.ajax=!!bV,d.support.cors=bV&&"withCredentials"in bV,bV=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),(!a.crossDomain||a.hasContent)&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bU[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bU||(bU={},bW()),h=bT++,g.onreadystatechange=bU[h]=c):c()},abort:function(){c&&c(0,1)}}}});var bZ={},b$=/^(?:toggle|show|hide)$/,b_=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,ca,cb=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(cc("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)e=this[g],f=e.style.display,!d._data(e,"olddisplay")&&f==="none"&&(f=e.style.display=""),f===""&&d.css(e,"display")==="none"&&d._data(e,"olddisplay",cd(e.nodeName));for(g=0;g<h;g++){e=this[g],f=e.style.display;if(f===""||f==="none")e.style.display=d._data(e,"olddisplay")||""}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cc("hide",3),a,b,c);for(var e=0,f=this.length;e<f;e++){var g=d.css(this[e],"display");g!=="none"&&!d._data(this[e],"olddisplay")&&d._data(this[e],"olddisplay",g)}for(e=0;e<f;e++)this[e].style.display="none";return this},_toggle:d.fn.toggle,toggle:function(a,b,c){var e=typeof a==="boolean";d.isFunction(a)&&d.isFunction(b)?this._toggle.apply(this,arguments):a==null||e?this.each(function(){var b=e?a:d(this).is(":hidden");d(this)[b?"show":"hide"]()}):this.animate(cc("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,e){var f=d.speed(b,c,e);if(d.isEmptyObject(a))return this.each(f.complete);return this[f.queue===!1?"each":"queue"](function(){var b=d.extend({},f),c,e=this.nodeType===1,g=e&&d(this).is(":hidden"),h=this;for(c in a){var i=d.camelCase(c);c!==i&&(a[i]=a[c],delete a[c],c=i);if(a[c]==="hide"&&g||a[c]==="show"&&!g)return b.complete.call(this);if(e&&(c==="height"||c==="width")){b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(d.css(this,"display")==="inline"&&d.css(this,"float")==="none")if(d.support.inlineBlockNeedsLayout){var j=cd(this.nodeName);j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)}else this.style.display="inline-block"}d.isArray(a[c])&&((b.specialEasing=b.specialEasing||{})[c]=a[c][1],a[c]=a[c][0])}b.overflow!=null&&(this.style.overflow="hidden"),b.curAnim=d.extend({},a),d.each(a,function(c,e){var f=new d.fx(h,b,c);if(b$.test(e))f[e==="toggle"?g?"show":"hide":e](a);else{var i=b_.exec(e),j=f.cur();if(i){var k=parseFloat(i[2]),l=i[3]||(d.cssNumber[c]?"":"px");l!=="px"&&(d.style(h,c,(k||1)+l),j=(k||1)/f.cur()*j,d.style(h,c,j+l)),i[1]&&(k=(i[1]==="-="?-1:1)*k+j),f.custom(j,k,l)}else f.custom(j,e,"")}});return!0})},stop:function(a,b){var c=d.timers;a&&this.queue([]),this.each(function(){for(var a=c.length-1;a>=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:cc("show",1),slideUp:cc("hide",1),slideToggle:cc("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!ca&&(ca=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||d.fx.stop()},interval:13,stop:function(){clearInterval(ca),ca=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){d.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),d.expr&&d.expr.filters&&(d.expr.filters.animated=function(a){return d.grep(d.timers,function(b){return a===b.elem}).length});var ce=/^t(?:able|d|h)$/i,cf=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?d.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,g=f.documentElement;if(!c||!d.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=f.body,i=cg(f),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||d.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||d.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:d.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);d.offset.initialize();var c,e=b.offsetParent,f=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(d.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===e&&(l+=b.offsetTop,m+=b.offsetLeft,d.offset.doesNotAddBorder&&(!d.offset.doesAddBorderForTableAndCells||!ce.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),f=e,e=b.offsetParent),d.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;d.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},d.offset={initialize:function(){var a=c.body,b=c.createElement("div"),e,f,g,h,i=parseFloat(d.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=cf.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!cf.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=cg(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=cg(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window);
Index: /branches/features/grailsUpgrade/web-app/js/jsUtil.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/jsUtil.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/jsUtil.js	(revision 875)
@@ -0,0 +1,129 @@
+
+function toggleUtil(id) {
+    $(id).toggle();
+}
+
+function toggleWithImgUtil(id, imageId, openImgUrl, closedImgUrl) {
+
+    $(id).toggle();
+
+    if( $(id).visible() ) {
+        $(imageId).src= openImgUrl;
+    }
+    else {
+        $(imageId).src= closedImgUrl;
+    }
+}
+
+function showUtil(id) {
+    Effect.Appear(id,{duration:0.2,queue:'end'});
+}
+
+function hideUtil(id) {
+    Effect.Fade(id,{duration:0.2,queue:'end'});
+}
+
+function toggleWithEffectUtil(id) {
+    if( $(id).visible() ) {
+        Effect.Fade(id,{duration:0.4,queue:'end'});
+    }
+    else {
+        Effect.Appear(id,{duration:0.4,queue:'end'});
+    }
+}
+
+function toggleWithImgAndEffectUtil(id, imageId, openImgUrl, closedImgUrl) {
+
+    if( $(id).visible() ) {
+        Effect.Fade(id,{duration:0.4,queue:'end'});
+        $(imageId).src= closedImgUrl;
+    }
+    else {
+        Effect.Appear(id,{duration:0.4,queue:'end'});
+        $(imageId).src= openImgUrl;
+    }
+}
+
+function textAreaScrollBottom(id) {
+    $(id).scrollTop = $(id).scrollHeight;
+}
+
+function focusUtil(id) {
+    $(id).focus();
+}
+
+function enableUtil(id) {
+    $(id).disabled = false;
+}
+
+function disableUtil(id) {
+    $(id).disabled = true;
+}
+
+// Looping in reverse is apparently more efficient.
+function containsUtil(val, array) {
+    var i = array.length;
+    while (i--) {
+        if (array[i] == val) {
+            return true;
+        }
+    }
+    return false;
+}
+
+function toggleArrayUtil(idArray) {
+    var i = idArray.length;
+    while (i--) {
+        toggleUtil(idArray[i]);
+    }
+}
+
+// Loops forwards.
+function showArrayUtil(idArray) {
+    var len = idArray.length
+    var i=0;
+    for (i=0; i < len; i++) {
+        Effect.Appear(idArray[i],{duration:0.05,queue:'end'});
+    }
+}
+
+// Loops backwards.
+function hideArrayUtil(idArray) {
+    var i = idArray.length;
+    while (i--) {
+        Effect.Fade(idArray[i],{duration:0.05,queue:'end'});
+    }
+}
+
+function disableArrayUtil(idArray) {
+    var i = idArray.length;
+    while (i--) {
+        disableUtil(idArray[i]);
+    }
+}
+
+function enableArrayUtil(idArray) {
+    var i = idArray.length;
+    while (i--) {
+        enableUtil(idArray[i]);
+    }
+}
+
+function toggleIfArrayContainsValueUtil(toggleIds, val, array) {
+    if(containsUtil(val, array)) {
+        //Effect.multiple(toggleIds, Effect.Appear, {duration:0.4,queue:'end'}); // A little slow, will not go bellow 0.1 per item.
+        showArrayUtil(toggleIds);
+    }
+    else {
+        hideArrayUtil(toggleIds);
+    }
+}
+
+function openWindow(url) {
+    window.open(url);
+}
+
+function getContextPath() {
+    var contextPath = '/' + location.pathname.split('/',2)[1]
+    return contextPath
+}
Index: /branches/features/grailsUpgrade/web-app/js/lightbox.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/lightbox.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/lightbox.js	(revision 875)
@@ -0,0 +1,731 @@
+//
+//	Lightbox version 3.0.0
+//	by Lokesh Dhakar - http://www.huddletogether.com
+//	04/03/2008
+//
+//	For more information on this script, visit:
+//	http://huddletogether.com/projects/lightbox2/
+//
+//	Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
+//
+//	Credit also due to those who have helped, inspired, and made their code available to the public.
+//	Including: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.org), Thomas Fuchs(mir.aculo.us), and others.
+//
+
+/*
+
+  Table of Contents
+  -----------------
+
+  Extending Built-in Objects
+  - Object.extend(Element)
+  - Array.prototype.removeDuplicates()
+
+  Lightbox Class Declaration
+  - block()
+  - onload()
+  - updateImageList()
+  
+  Miscellaneous Functions
+  - getPageScroll()
+  - getPageSize()
+  - showSelectBoxes()
+  - hideSelectBoxes()
+  - showObjects()
+  - hideObjects()
+  - pause()
+
+*/
+
+//	Additional methods for Element added by SU, Couloir
+//	- further additions by Lokesh Dhakar (huddletogether.com)
+Object.extend(Element, {
+  setWidth: function (element, width) {
+    $(element).style.width = width + "px";
+  },
+  setHeight: function (element, height) {
+    $(element).style.height = height + "px";
+  },
+  setTop: function (element, top) {
+    $(element).style.top = top + "px";
+  },
+  setLeft: function (element, left) {
+    $(element).style.left = left + "px";
+  },
+  setSrc: function (element, src) {
+    $(element).src = src;
+  },
+  setInnerHTML: function (element, content) {
+    $(element).innerHTML = content;
+  }
+});
+
+//	Extending built-in Array object
+//	- array.removeDuplicates()
+Array.prototype.removeDuplicates = function () {
+  for (i = 1; i < this.length; i++) {
+    if (this[i][0] == this[i - 1][0]) { this.splice(i, 1); }
+  }
+}
+
+//	Lightbox Class Declaration
+//	- block()
+//  - onload()
+//  - updateImageList()
+
+//	Structuring of code inspired by Scott Upton (http://www.uptonic.com/)
+
+var Lightbox = {
+
+  onload: function (event) {
+
+    // preload image.
+    loadingImage = new Image();
+    loadingImage.src =  Lightbox._imagePath + "loading.gif";
+
+    var options = { 'minWidth' : 650};
+    return Lightbox._create(options);
+  },
+
+  // Fades to overlay and runs an animated loading gif (e.g after form submit)
+  loading: function(options) {
+    if (!document.getElementsByTagName) { return true; }
+
+     Lightbox._options(options);
+
+     var buttons = document.getElementsByClassName("buttons");
+     buttons[0].style.visibility = "hidden";
+
+    var parent = document.getElementsByTagName("body").item(0);
+    var overlay = Lightbox._createElement("div", "overlay", "none", null, null, function (event) {} );
+    parent.appendChild(overlay);
+
+    var pageSize = getPageSize();
+    Element.setWidth('overlay', pageSize[0]);
+    Element.setHeight('overlay', pageSize[1]);
+
+    if (Lightbox._animate) {
+      new Effect.Appear('overlay', { duration: Lightbox._overlayBlockDuration, from: 0.0, to: Lightbox._blockOpacity });
+    }
+    else {
+      Element.setOpacity('overlay', Lightbox._opacity);
+    }
+
+    if (Lightbox._animate) {
+        var loading = Lightbox._createElement("div", 'loading');
+        parent.appendChild(loading);
+
+        // document.all should be detected in IE and Opera, workaround for IE gif freezing.
+        if(document.all) {
+            new Effect.Pulsate(loading, { pulses: 800, duration: 532 });
+        }
+        else {
+            Element.show('loading');
+        }
+    }
+
+  },
+
+
+  // Blocks the page (after form submit)
+  block: function(message, options) {
+    if (!document.getElementsByTagName) { return true; }
+
+    Lightbox._options(options);
+    
+    var parent = document.getElementsByTagName("body").item(0);
+    var overlay = Lightbox._createElement("div", "overlay", "none", null, null, function (event) {} );
+    parent.appendChild(overlay);
+        
+    // The rest of this code inserts html at the bottom of the page that looks similar to this:
+    //
+    // <div id="lightbox">
+    //   <div id="outerImageContainer">
+    //     <div id="imageContainer">
+    //       <div id="loading"></div>
+    //       <div id="imageDataContainer"> message </div>
+    //     </div>
+    //   </div>
+    // </div>
+
+    var lightbox = Lightbox._createElement("div", "lightbox", "none");
+    parent.appendChild(lightbox);
+
+    var outerImageContainer = Lightbox._createElement("div", "outerImageContainer");
+    lightbox.appendChild(outerImageContainer);
+
+    var imageContainer = Lightbox._createElement("div", 'imageContainer');
+    outerImageContainer.appendChild(imageContainer);
+
+	imageContainer.appendChild(Lightbox._createElement("div", 'loading'));
+    imageDataContainer = Lightbox._createElement("div", 'imageDataContainer');
+    imageContainer.appendChild(imageDataContainer);
+    imageDataContainer.appendChild(document.createTextNode(message));
+
+    hideSelectBoxes();
+    hideObjects();
+    var pageSize = getPageSize();
+    Element.setWidth('overlay', pageSize[0]);
+    Element.setHeight('overlay', pageSize[1]);
+    Element.setOpacity('overlay', Lightbox._blockOpacity);
+    Element.show('overlay');
+    Element.setTop('lightbox', Number(getPageScroll()[1] + (getPageSize()[3] / 15)).toFixed());
+    Element.show('lightbox');
+    Element.show('loading');
+    return true;
+  },
+  
+  // Loops through anchor tags looking for 'lightbox' references and applies onclick
+  // events to appropriate links. You can rerun after dynamically adding images w/ajax.
+  updateImageList: function () {
+    if (!document.getElementsByTagName) { return; }
+
+    // loop through all anchor tags
+    var anchors = document.getElementsByTagName('a');
+    for (var i = 0, l = anchors.length; i < l; i++) {
+      var anchor = anchors[i];
+      // use the string.match() method to catch 'lightbox' references in the rel attribute
+      var relAttribute = String(anchor.getAttribute('rel'));
+      if (anchor.getAttribute('href') && (relAttribute.toLowerCase().match('lightbox'))) {
+        anchor.onclick = function () { return Lightbox._start(this); };
+      }
+    }
+
+    // loop through all area tags
+    // todo: combine anchor & area tag loops
+    var areas = document.getElementsByTagName('area');
+    for (var i = 0, l = areas.length; i < l; i++) {
+      var area = areas[i];
+      // use the string.match() method to catch 'lightbox' references in the rel attribute
+      var relAttribute = String(area.getAttribute('rel'));
+      if (area.getAttribute('href') && (relAttribute.toLowerCase().match('lightbox'))) {
+        Area.onclick = function () { return Lightbox.start(this); }
+      }
+    }
+  },
+
+  // Loops through anchor tags looking for 'lightbox' references and applies onclick events 
+  // to appropriate links. The 2nd section of the function inserts html at the bottom of the 
+  // page which is used to display the shadow overlay and the image container.
+  _create: function(options) {
+    if (!document.getElementsByTagName) return;
+
+    Lightbox._options(options);
+
+    var parent = document.getElementsByTagName("body").item(0);
+    var overlay = Lightbox._createElement("div", "overlay", "none", null, null, Lightbox._overlayEnd);
+    parent.appendChild(overlay);
+
+    Lightbox.updateImageList();
+        
+    // The rest of this code inserts html at the bottom of the page that looks similar to this:
+    //
+    // <div id="lightbox">
+    //   <div id="outerImageContainer">
+    //     <div id="imageContainer">
+    //       <img id="lightboxImage" />
+    //       <div id="hoverNav">
+    //         <a href="#" id="prevLink"></a>
+    //         <a href="#" id="nextLink"></a>
+    //       </div>
+    //       <div id="loading"></div>
+    //     </div>
+    //   </div>
+    //   <div id="imageDataContainer">
+    //     <div id="imageData">
+    //       <div id="imageDetails">
+    //         <span id="caption"></span>
+    //         <span id="numberDisplay"></span>
+    //       </div>
+    //       <div id="bottomNav">
+    //         <img id="bottomNavPrev" />
+    //         <img id="bottomNavNext" />
+    //         <img id="bottomNavClose" />
+    //       </div>
+    //     </div>
+    //   </div>
+    // </div>
+
+    var lightbox = Lightbox._createElement("div", "lightbox", "none", null, null, Lightbox._overlayEnd);
+    parent.appendChild(lightbox);
+
+    var outerImageContainer = Lightbox._createElement("div", "outerImageContainer");
+    lightbox.appendChild(outerImageContainer);
+
+    // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
+    // If animations are turned off, it will be hidden as to prevent a flicker of a
+    // white 250 by 250 box.
+    if (Lightbox._animate) {
+      Element.setWidth('outerImageContainer', 250);
+      Element.setHeight('outerImageContainer', 250);
+    }
+    else {
+      Element.setWidth('outerImageContainer', 1);
+      Element.setHeight('outerImageContainer', 1);
+    }
+
+    var imageContainer = Lightbox._createElement("div", 'imageContainer');
+    outerImageContainer.appendChild(imageContainer);
+    imageContainer.appendChild(Lightbox._createElement("img", 'lightboxImage'));
+
+    var hoverNav = Lightbox._createElement("div", 'hoverNav');
+    imageContainer.appendChild(hoverNav);
+
+    hoverNav.appendChild(Lightbox._createElement("a", 'prevLink', null, null, '#'));
+    hoverNav.appendChild(Lightbox._createElement("a", 'nextLink', null, null, '#'));
+
+    imageContainer.appendChild(Lightbox._createElement("div", 'loading', null, null, null, Lightbox._end));
+
+    imageDataContainer = Lightbox._createElement("div", 'imageDataContainer');
+    lightbox.appendChild(imageDataContainer);
+
+    imageData = Lightbox._createElement("div", 'imageData');
+    imageDataContainer.appendChild(imageData);
+
+    var imageDetails = Lightbox._createElement("div", 'imageDetails');
+    imageData.appendChild(imageDetails);
+
+    imageDetails.appendChild(Lightbox._createElement("span", 'caption'));
+    imageDetails.appendChild(Lightbox._createElement("span", 'numberDisplay'));
+
+    bottomNav = Lightbox._createElement("div", 'bottomNav');
+    imageData.appendChild(bottomNav);
+
+    bottomNav.appendChild(Lightbox._createElement("img", 'bottomNavPrev',  null, Lightbox._imagePath + "miniprev.jpg",   null, Lightbox._prevImage));
+    bottomNav.appendChild(Lightbox._createElement("img", 'bottomNavNext',  null, Lightbox._imagePath + "mininext.jpg",   null, Lightbox._nextImage));
+    bottomNav.appendChild(Lightbox._createElement("img", 'bottomNavClose', null, Lightbox._imagePath + "closelabel.gif", null, Lightbox._end));
+  },
+
+  _createElement: function (type, id, display, src, href, onclick) {
+    elem = document.createElement(type);
+    if (id)      { elem.setAttribute('id', id); }
+    if (display) { elem.style.display = display; }
+    if (src)     { elem.setAttribute('src', src); }
+    if (href)    { elem.setAttribute('href', href); }
+	if (onclick) { elem.onclick = onclick; }
+    return elem;
+  },
+
+  _options: function(options) {
+    if (options) {
+      var option = options['borderSize'];
+      if (option) { Lightbox._borderSize = option; }
+      option = options['overlayDuration'];
+      if (option) { Lightbox._overlayDuration = option; }
+      option = options['resizeDuration'];
+      if (option) { Lightbox._resizeDuration = option; }
+      option = options['minWidth'];
+      if (option) { Lightbox._minWidth = option; }
+      option = options['imagePath'];
+      if (option) { Lightbox._imagePath = option; }
+      option = options['opacity'];
+      if (option) { Lightbox._opacity = option; }
+      option = options['blockOpacity'];
+      if (option) { Lightbox._blockOpacity = option; }
+      option = options['animate'];
+      if (option) { Lightbox._animate = option; }
+      option = options['text'];
+      if (option) { Lightbox._text = option; }
+    }    
+  },
+
+  // Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
+  _start: function (imageLink) {
+    hideSelectBoxes();
+    hideObjects();
+
+    // stretch overlay to fill page and fade in
+    var pageSize = getPageSize();
+    Element.setWidth('overlay', pageSize[0]);
+    Element.setHeight('overlay', pageSize[1]);
+
+    if (Lightbox._animate) {
+      new Effect.Appear('overlay', { duration: Lightbox._overlayDuration, from: 0.0, to: Lightbox._opacity });
+    }
+    else {
+      Element.setOpacity('overlay', Lightbox._opacity);
+    }
+
+    Lightbox._activeImage = 0;
+    Lightbox._imageArray = [];
+    var imageNum = 0;
+    if ((imageLink.getAttribute('rel') == 'lightbox')) { // if image is NOT part of a set..
+	  Lightbox._imageArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title')));
+    }
+    else { // if image is part of a set..
+      // loop through anchors, find other images in set, and add them to imageArray
+      var rel = imageLink.getAttribute('rel');
+      var anchors = document.getElementsByTagName(imageLink.tagName);
+      for (var i = 0, l = anchors.length; i < l; i++) {
+        var anchor = anchors[i];
+        if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == rel)) {
+          Lightbox._imageArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title')));
+        }
+      }
+      Lightbox._imageArray.removeDuplicates();
+      var href = imageLink.getAttribute('href');
+      while (Lightbox._imageArray[imageNum][0] != href) { imageNum++; }
+    }
+
+    // calculate top offset for the lightbox and display
+    var pageScroll = getPageScroll();
+    Element.setTop('lightbox', Number(pageScroll[1] + (pageSize[3] / 10)).toFixed());
+    Element.setLeft('lightbox', Number(pageScroll[0]).toFixed());
+    Element.show('lightbox');
+    Lightbox._changeImage(imageNum);
+    return false;
+  },
+
+  _overlayEnd: function (event) {
+    if (!event) { event = window.event; }
+    var id = Event.element(event).id;
+    if (id == 'overlay' || id == 'lightbox') { return Lightbox._end(); }
+    return true;
+  },
+
+  _end: function (event) {
+    Lightbox._disableKeyboardNav();
+    Element.hide('lightbox');
+    if (Lightbox._animate) {
+      new Effect.Fade('overlay', { duration: Lightbox._overlayDuration });
+    } 
+    else {
+      Element.hide('overlay');
+    }
+    showSelectBoxes();
+    showObjects();
+    return false;
+  },
+
+  _hasNext: function () {
+    return Lightbox._activeImage < (Lightbox._imageArray.length - 1);
+  },
+
+  _nextImage: function () {
+    Lightbox._changeImage(Lightbox._activeImage + 1);
+    return false;
+  },
+
+  _hasPrev: function () {
+    return Lightbox._activeImage > 0;
+  },
+
+  _prevImage: function () {
+    Lightbox._changeImage(Lightbox._activeImage - 1);
+    return false;
+  },
+
+  // Hide most elements and preload image in preparation for resizing image container.
+  _changeImage: function (imageNum) {
+    Lightbox._activeImage = imageNum;
+    
+    // hide elements during transition
+    if (Lightbox._animate) { Element.show('loading'); }
+    Element.hide('lightboxImage');
+    Element.hide('hoverNav');
+    Element.hide('prevLink');
+    Element.hide('nextLink');
+    Element.hide('bottomNavPrev');
+    Element.hide('bottomNavNext');
+    Element.hide('imageDataContainer');
+    Element.hide('caption');
+    Element.hide('numberDisplay');
+
+    // once image is preloaded, resize image container
+    Lightbox._preloader = new Image();
+    Lightbox._preloader.onload = function () {
+      Element.setSrc('lightboxImage', Lightbox._imageArray[imageNum][0]);
+      Lightbox._preloader.onload = function () { }; // clear onLoad, IE behaves irratically with animated gifs otherwise 
+      Lightbox._resizeImageContainer(Lightbox._preloader.width, Lightbox._preloader.height);
+    };
+    Lightbox._preloader.src = Lightbox._imageArray[imageNum][0];
+  },
+
+  _resizeImageContainer: function (imgWidth, imgHeight) {
+    var borders = Lightbox._borderSize * 2;
+    
+    // keep to a minimum width, if specified
+    if (Lightbox._minWidth > 0 && (imgWidth + borders) < Lightbox._minWidth) {
+      imgWidth = Lightbox._minWidth - borders;
+    }
+
+    // get current height and width
+    var widthCurrent = Element.getWidth('outerImageContainer');
+    var heightCurrent = Element.getHeight('outerImageContainer');
+
+    // get new width and height
+    var widthNew = imgWidth + borders;
+    var heightNew = imgHeight + borders;
+
+    // scalars based on change from old to new
+    var xScale = (widthNew / widthCurrent) * 100;
+    var yScale = (heightNew / heightCurrent) * 100;
+    
+    // calculate size difference between new and old image, and resize if necessary
+    var widthDiff = widthCurrent - widthNew;
+	var heightDiff = heightCurrent - heightNew;
+    if (heightDiff != 0) {
+      new Effect.Scale('outerImageContainer', yScale, { scaleX: false, duration: Lightbox._resizeDuration, queue: 'front' });
+    }
+	if (widthDiff != 0) {
+	  new Effect.Scale('outerImageContainer', xScale, { scaleY: false, duration: Lightbox._resizeDuration, delay: Lightbox._resizeDuration });
+	}
+
+    // if new and old image are same size and no scaling transition is necessary,
+    // do a quick pause to prevent image flicker.
+    if ((heightDiff == 0) && (widthDiff == 0)) {
+      if (navigator.appVersion.indexOf("MSIE") != -1) { pause(250); } else { pause(100); }
+    }
+
+    Element.setHeight('prevLink', imgHeight);
+    Element.setHeight('nextLink', imgHeight);
+    Element.setWidth('imageDataContainer', widthNew);
+    Lightbox._showImage();
+  },
+
+  // Display image.
+  _showImage: function () {
+    Element.hide('loading');
+    new Effect.Appear('lightboxImage', { duration: Lightbox._resizeDuration, queue: 'end', afterFinish: Lightbox._updateDetails });
+	Lightbox._preloadNeighborImages();
+  },
+
+  // Display caption, image number, and bottom nav.
+  _updateDetails: function () {
+    // if caption is not null
+	var caption = Lightbox._imageArray[Lightbox._activeImage][1];
+    if (caption) {
+      Element.show('caption');
+      Element.setInnerHTML('caption', caption);
+    }
+		
+    // if image is part of set display 'Image x of x'
+    if (Lightbox._imageArray.length > 1) {
+      Element.show('numberDisplay');
+      var text = Lightbox._text.replace("*", (Lightbox._activeImage + 1));
+      text = text.replace("*", Lightbox._imageArray.length);
+      Element.setInnerHTML('numberDisplay', text);
+    } 
+
+    if (Lightbox._hasPrev()) { Element.show('bottomNavPrev'); }	
+    if (Lightbox._hasNext()) { Element.show('bottomNavNext'); }
+
+	new Effect.Parallel(
+	  [ new Effect.SlideDown('imageDataContainer', { sync: true, duration: Lightbox._resizeDuration }),
+        new Effect.Appear('imageDataContainer', { sync: true, duration: Lightbox._resizeDuration }) ],
+      { duration: Lightbox._resizeDuration, afterFinish: Lightbox._updateNav });
+  },
+
+  // Display appropriate previous and next hover navigation.
+  _updateNav: function () {
+    $('imageDataContainer').style.overflow = 'auto'; // css float fix
+
+    Element.setHeight('overlay', getPageSize()[1]);
+
+    Element.show('hoverNav');
+
+    // if not first image in set, display prev image button
+    if (Lightbox._hasPrev()) {
+      document.getElementById('prevLink').onclick = Lightbox._prevImage;
+      Element.show('prevLink');
+      }
+
+    // if not last image in set, display next image button
+    if (Lightbox._hasNext()) {
+      document.getElementById('nextLink').onclick = Lightbox._nextImage;
+      Element.show('nextLink');
+    }
+   Lightbox._enableKeyboardNav();
+  },
+
+  _enableKeyboardNav: function () {
+    document.onkeydown = Lightbox._keyboardAction;
+  },
+
+  _disableKeyboardNav: function () {
+    document.onkeydown = '';
+  },
+
+  _keyboardAction: function (evnt) {
+    var keycode = 0, escapeKey = 0, key = 0;
+    if (evnt == null) { // ie
+      keycode = event.keyCode;
+      escapeKey = 27;
+    }
+    else { // mozilla
+      keycode = evnt.keyCode;
+      escapeKey = evnt.DOM_VK_ESCAPE;
+    }
+
+    key = String.fromCharCode(keycode).toLowerCase();
+    if ((key == 'x') || (key == 'o') || (key == 'c') || (keycode == escapeKey)) { // close lightbox
+      Lightbox._end();
+      return true;
+    } 
+    else if((key == 'p') || (keycode == 37)) { // display previous image
+      if (Lightbox._hasPrev()) {
+        Lightbox._disableKeyboardNav();
+        Lightbox._prevImage();
+        return true;
+      }
+    } 
+    else if((key == 'n') || (keycode == 39)) { // display next image
+      if (Lightbox._hasNext()) {
+        Lightbox._disableKeyboardNav();
+        Lightbox._nextImage();
+        return true;
+      }
+    }
+  return false;
+  },
+
+  _preloadNeighborImages: function () {
+    if (Lightbox._hasNext()) {
+      Lightbox._preloadNextImage = new Image();
+      Lightbox._preloadNextImage.src = Lightbox._imageArray[Lightbox._activeImage + 1][0];
+    }
+    if (Lightbox._hasPrev()) {
+      Lightbox._preloadPrevImage = new Image();
+      Lightbox._preloadPrevImage.src = Lightbox._imageArray[Lightbox._activeImage - 1][0];
+    }
+  },
+
+  _borderSize: 10,
+  _overlayDuration: 0.2,
+  _overlayBlockDuration: 0.6,
+  _resizeDuration: 0.4,
+  _minWidth: 0,
+  _imagePath: '/' + location.pathname.split('/',2)[1] + '/images/',
+  _opacity: 0.6,
+  _blockOpacity: 0.1,
+  _animate: true,
+  _text: "Image * of *",
+  _activeImage: 0,
+  _imageArray: []
+}
+
+// Returns array with x, y page scroll values.
+// Core code from - quirksmode.org
+function getPageScroll(){
+  var xScroll = 0, yScroll = 0;
+  if (self.pageYOffset) {
+    xScroll = self.pageXOffset;
+    yScroll = self.pageYOffset;
+  }
+  else if (document.documentElement && document.documentElement.scrollTop) {	// Explorer 6 Strict
+    xScroll = document.documentElement.scrollLeft;
+    yScroll = document.documentElement.scrollTop;
+  } 
+  else if (document.body) { // all other Explorers
+    xScroll = document.body.scrollLeft;	
+    yScroll = document.body.scrollTop;
+  }
+  return new Array(xScroll, yScroll)
+}
+
+// Returns array with page width, height and window width, height
+// Core code from - quirksmode.org
+// Edit for Firefox by pHaez
+function getPageSize() {
+  var xScroll = 0, yScroll = 0;
+  var docBody = document.body;
+  var docElem = document.documentElement;
+  if (window.innerHeight && window.scrollMaxY) {
+    xScroll = window.innerWidth + window.scrollMaxX;
+    yScroll = window.innerHeight + window.scrollMaxY;
+  }
+  else if (docBody.scrollHeight > docBody.offsetHeight) { // all but Explorer Mac
+    xScroll = docBody.scrollWidth;
+    yScroll = docBody.scrollHeight;
+  } 
+  else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
+    xScroll = docBody.offsetWidth;
+    yScroll = docBody.offsetHeight;
+  }
+
+  var windowWidth = 0, windowHeight = 0, pageHeight = 0, pageWidth = 0;
+  if (self.innerHeight) {	// all except Explorer
+    if(docElem.clientWidth) {
+      windowWidth = docElem.clientWidth; 
+    }
+    else {
+      windowWidth = self.innerWidth;
+    }
+    windowHeight = self.innerHeight;
+  }
+  else if (docElem && docElem.clientHeight) { // Explorer 6 Strict Mode
+    windowWidth = docElem.clientWidth;
+    windowHeight = docElem.clientHeight;
+  }
+  else { // other Explorers
+    windowWidth = docBody.clientWidth;
+    windowHeight = docBody.clientHeight;
+  }
+
+  // for small pages with total height less then height of the viewport
+  if (yScroll < windowHeight) {
+    pageHeight = windowHeight;
+  }	
+  else {
+    pageHeight = yScroll;
+  }
+
+  // for small pages with total width less then width of the viewport
+  if (xScroll < windowWidth) {
+    pageWidth = xScroll;
+  }
+  else {
+    pageWidth = windowWidth;
+  }
+  return new Array(pageWidth, pageHeight, windowWidth, windowHeight)
+}
+
+function showSelectBoxes() {
+  var selects = document.getElementsByTagName("select");
+  for (var i = 0, l = selects.length; i < l; i++) {
+    selects[i].style.visibility = "visible";
+  }
+}
+
+function hideSelectBoxes() {
+  var selects = document.getElementsByTagName("select");
+  for (var i = 0, l = selects.length; i < l; i++) {
+    selects[i].style.visibility = "hidden";
+  }
+}
+
+function showObjects() {
+  var objects = document.getElementsByTagName("object");
+  for (var i = 0, l = objects.length; i < l; i++) {
+    objects[i].style.visibility = "visible";
+  }
+
+  var embeds = document.getElementsByTagName("embed");
+  for (var i = 0, l = embeds.length; i < l; i++) {
+    embeds[i].style.visibility = "visible";
+  }
+}
+
+function hideObjects() {
+  var objects = document.getElementsByTagName("object");
+  for (var i = 0, l = objects.length; i < l; i++) {
+    objects[i].style.visibility = "hidden";
+  }
+
+  var embeds = document.getElementsByTagName("embed");
+  for (var i = 0, l = embeds.length; i < l; i++) {
+    embeds[i].style.visibility = "hidden";
+  }
+}
+
+// pause(numberMillis)
+// Pauses code execution for specified time. Uses busy code, not good.
+// Code from http://www.faqts.com/knowledge_base/view.phtml/aid/1602
+// Help from Ran Bar-On [ran2103@gmail.com]
+function pause(ms) {
+  var date = new Date();
+  var curDate = null;
+  do {
+    curDate = new Date();
+  } while (curDate - date < ms);
+}
Index: /branches/features/grailsUpgrade/web-app/js/overlayPane.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/overlayPane.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/overlayPane.js	(revision 875)
@@ -0,0 +1,77 @@
+
+function showElement(id) {
+    try {
+        if (typeof Effect != "undefined" && typeof Effect.Appear != "undefined") {
+                    if ($(id) && Element.visible(id) == false)
+            Effect.Appear(id,{duration:0.4,queue:'end'});
+        } else {
+            var el = document.getElementById(id)
+            if (el && el.style.display == 'none') {
+                el.style.display = 'block';
+            }
+        }
+    } catch (err) {alert(err)}
+    return false;
+}
+
+function hideElement(id) {
+    if (typeof Effect != "undefined" && typeof Effect.Fade != "undefined") {
+            if ($(id) && Element.visible(id))
+        Effect.Fade(id,{duration:0.4,queue:'end'});
+    } else {
+        var el = document.getElementById(id)
+        if (el && el.style.display != 'none') {
+            el.style.display = 'none';
+        }
+    }
+    return false;
+}
+
+function clearFilterPane(id) {
+    var form = document.getElementById(id)
+
+    for (var i = 0; i < form.elements.length; i++) {
+        var el = form.elements[i]
+        if (el.type == 'select-one') {
+            el.selectedIndex = 0
+        } else if (el.type == 'text' || el.type == 'textarea') { 
+            form.elements[i].value = ''
+        }
+    }
+}
+
+function filterOpChange(id, controlId) {
+    // id should be of the form op.propertyName
+    if (id.slice(0, 10) == 'filter.op.') {
+        var prop = id.substring(10)
+        var el = document.getElementById(id)
+        var selection = el.options[el.selectedIndex]
+        if (el) {
+            if (el.type == 'select-one') {
+                if (selection.value == 'Between') {
+                    showElement('between-span-'+prop)
+                } else {
+                    hideElement('between-span-'+prop)
+                }
+            }
+
+            var containerName = prop+'-container'
+            if (selection.value == 'IsNull' || selection.value == 'IsNotNull') {
+                hideElement(controlId);
+                // Take care of date picker fields we created.
+                if (document.getElementById(containerName)) hideElement(containerName)
+            } else {
+                showElement(controlId);
+                // Take care of date picker fields.
+                if (document.getElementById(containerName)) showElement(containerName)
+            }
+        }
+    }
+}
+
+function selectDefaultOperator(id) {
+    var dropdown = document.getElementById(id)
+    if (dropdown && dropdown.selectedIndex <= 0) {
+        dropdown.selectedIndex = 1
+    }
+}
Index: /branches/features/grailsUpgrade/web-app/js/prototype/animation.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/animation.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/animation.js	(revision 875)
@@ -0,0 +1,7 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.10.0
+*/
+YAHOO.util.Anim=function(el,attributes,duration,method){if(el){this.init(el,attributes,duration,method);}};YAHOO.util.Anim.prototype={doMethod:function(attribute,start,end){return this.method(this.currentFrame,start,end-start,this.totalFrames);},setAttribute:function(attribute,val,unit){YAHOO.util.Dom.setStyle(this.getEl(),attribute,val+unit);},getAttribute:function(attribute){return parseFloat(YAHOO.util.Dom.getStyle(this.getEl(),attribute));},defaultUnit:'px',defaultUnits:{opacity:' '},init:function(el,attributes,duration,method){var isAnimated=false;var startTime=null;var endTime=null;var actualFrames=0;var defaultValues={};el=YAHOO.util.Dom.get(el);this.attributes=attributes||{};this.duration=duration||1;this.method=method||YAHOO.util.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=YAHOO.util.AnimMgr.fps;this.getEl=function(){return el;};this.setDefault=function(attribute,val){if(val.constructor!=Array&&(val=='auto'||isNaN(val))){switch(attribute){case'width':val=el.clientWidth||el.offsetWidth;break;case'height':val=el.clientHeight||el.offsetHeight;break;case'left':if(YAHOO.util.Dom.getStyle(el,'position')=='absolute'){val=el.offsetLeft;}else{val=0;}break;case'top':if(YAHOO.util.Dom.getStyle(el,'position')=='absolute'){val=el.offsetTop;}else{val=0;}break;default:val=0;}}defaultValues[attribute]=val;};this.getDefault=function(attribute){return defaultValues[attribute];};this.isAnimated=function(){return isAnimated;};this.getStartTime=function(){return startTime;};this.animate=function(){if(this.isAnimated()){return false;}this.onStart.fire();this._onStart.fire();this.totalFrames=(this.useSeconds)?Math.ceil(YAHOO.util.AnimMgr.fps*this.duration):this.duration;YAHOO.util.AnimMgr.registerElement(this);var attributes=this.attributes;var el=this.getEl();var val;for(var attribute in attributes){val=this.getAttribute(attribute);this.setDefault(attribute,val);}isAnimated=true;actualFrames=0;startTime=new Date();};this.stop=function(){if(!this.isAnimated()){return false;}this.currentFrame=0;endTime=new Date();var data={time:endTime,duration:endTime-startTime,frames:actualFrames,fps:actualFrames/this.duration};isAnimated=false;actualFrames=0;this.onComplete.fire(data);};var onTween=function(){var start;var end=null;var val;var unit;var attributes=this['attributes'];for(var attribute in attributes){unit=attributes[attribute]['unit']||this.defaultUnits[attribute]||this.defaultUnit;if(typeof attributes[attribute]['from']!='undefined'){start=attributes[attribute]['from'];}else{start=this.getDefault(attribute);}if(typeof attributes[attribute]['to']!='undefined'){end=attributes[attribute]['to'];}else if(typeof attributes[attribute]['by']!='undefined'){if(start.constructor==Array){end=[];for(var i=0,len=start.length;i<len;++i){end[i]=start[i]+attributes[attribute]['by'][i];}}else{end=start+attributes[attribute]['by'];}}if(end!==null&&typeof end!='undefined'){val=this.doMethod(attribute,start,end);if((attribute=='width'||attribute=='height'||attribute=='opacity')&&val<0){val=0;}this.setAttribute(attribute,val,unit);}}actualFrames+=1;};this._onStart=new YAHOO.util.CustomEvent('_onStart',this);this.onStart=new YAHOO.util.CustomEvent('start',this);this.onTween=new YAHOO.util.CustomEvent('tween',this);this._onTween=new YAHOO.util.CustomEvent('_tween',this);this.onComplete=new YAHOO.util.CustomEvent('complete',this);this._onTween.subscribe(onTween);}};YAHOO.util.AnimMgr=new function(){var thread=null;var queue=[];var tweenCount=0;this.fps=200;this.delay=1;this.registerElement=function(tween){if(tween.isAnimated()){return false;}queue[queue.length]=tween;tweenCount+=1;this.start();};this.start=function(){if(thread===null){thread=setInterval(this.run,this.delay);}};this.stop=function(tween){if(!tween){clearInterval(thread);for(var i=0,len=queue.length;i<len;++i){if(queue[i].isAnimated()){queue[i].stop();}}queue=[];thread=null;tweenCount=0;}else{tween.stop();tweenCount-=1;if(tweenCount<=0){this.stop();}}};this.run=function(){for(var i=0,len=queue.length;i<len;++i){var tween=queue[i];if(!tween||!tween.isAnimated()){continue;}if(tween.currentFrame<tween.totalFrames||tween.totalFrames===null){tween.currentFrame+=1;if(tween.useSeconds){correctFrame(tween);}tween.onTween.fire();tween._onTween.fire();}else{YAHOO.util.AnimMgr.stop(tween);}}};var correctFrame=function(tween){var frames=tween.totalFrames;var frame=tween.currentFrame;var expected=(tween.currentFrame*tween.duration*1000/tween.totalFrames);var elapsed=(new Date()-tween.getStartTime());var tweak=0;if(elapsed<tween.duration*1000){tweak=Math.round((elapsed/expected-1)*tween.currentFrame);}else{tweak=frames-(frame+1);}if(tweak>0&&isFinite(tweak)){if(tween.currentFrame+tweak>=frames){tweak=frames-(frame+1);}tween.currentFrame+=tweak;}};};YAHOO.util.Bezier=new function(){this.getPosition=function(points,t){var n=points.length;var tmp=[];for(var i=0;i<n;++i){tmp[i]=[points[i][0],points[i][1]];}for(var j=1;j<n;++j){for(i=0;i<n-j;++i){tmp[i][0]=(1-t)*tmp[i][0]+t*tmp[parseInt(i+1,10)][0];tmp[i][1]=(1-t)*tmp[i][1]+t*tmp[parseInt(i+1,10)][1];}}return[tmp[0][0],tmp[0][1]];};};YAHOO.util.Easing=new function(){this.easeNone=function(t,b,c,d){return b+c*(t/=d);};this.easeIn=function(t,b,c,d){return b+c*((t/=d)*t*t);};this.easeOut=function(t,b,c,d){var ts=(t/=d)*t;var tc=ts*t;return b+c*(tc+-3*ts+3*t);};this.easeBoth=function(t,b,c,d){var ts=(t/=d)*t;var tc=ts*t;return b+c*(-2*tc+3*ts);};this.backIn=function(t,b,c,d){var ts=(t/=d)*t;var tc=ts*t;return b+c*(-3.4005*tc*ts+10.2*ts*ts+-6.2*tc+0.4*ts);};this.backOut=function(t,b,c,d){var ts=(t/=d)*t;var tc=ts*t;return b+c*(8.292*tc*ts+-21.88*ts*ts+22.08*tc+-12.69*ts+5.1975*t);};this.backBoth=function(t,b,c,d){var ts=(t/=d)*t;var tc=ts*t;return b+c*(0.402*tc*ts+-2.1525*ts*ts+-3.2*tc+8*ts+-2.05*t);};};YAHOO.util.Motion=function(el,attributes,duration,method){if(el){this.initMotion(el,attributes,duration,method);}};YAHOO.util.Motion.prototype=new YAHOO.util.Anim();YAHOO.util.Motion.prototype.defaultUnits.points='px';YAHOO.util.Motion.prototype.doMethod=function(attribute,start,end){var val=null;if(attribute=='points'){var translatedPoints=this.getTranslatedPoints();var t=this.method(this.currentFrame,0,100,this.totalFrames)/100;if(translatedPoints){val=YAHOO.util.Bezier.getPosition(translatedPoints,t);}}else{val=this.method(this.currentFrame,start,end-start,this.totalFrames);}return val;};YAHOO.util.Motion.prototype.getAttribute=function(attribute){var val=null;if(attribute=='points'){val=[this.getAttribute('left'),this.getAttribute('top')];if(isNaN(val[0])){val[0]=0;}if(isNaN(val[1])){val[1]=0;}}else{val=parseFloat(YAHOO.util.Dom.getStyle(this.getEl(),attribute));}return val;};YAHOO.util.Motion.prototype.setAttribute=function(attribute,val,unit){if(attribute=='points'){YAHOO.util.Dom.setStyle(this.getEl(),'left',val[0]+unit);YAHOO.util.Dom.setStyle(this.getEl(),'top',val[1]+unit);}else{YAHOO.util.Dom.setStyle(this.getEl(),attribute,val+unit);}};YAHOO.util.Motion.prototype.initMotion=function(el,attributes,duration,method){YAHOO.util.Anim.call(this,el,attributes,duration,method);attributes=attributes||{};attributes.points=attributes.points||{};attributes.points.control=attributes.points.control||[];this.attributes=attributes;var start;var end=null;var translatedPoints=null;this.getTranslatedPoints=function(){return translatedPoints;};var translateValues=function(val,self){var pageXY=YAHOO.util.Dom.getXY(self.getEl());val=[val[0]-pageXY[0]+start[0],val[1]-pageXY[1]+start[1]];return val;};var onStart=function(){start=this.getAttribute('points');var attributes=this.attributes;var control=attributes['points']['control']||[];if(control.length>0&&control[0].constructor!=Array){control=[control];}if(YAHOO.util.Dom.getStyle(this.getEl(),'position')=='static'){YAHOO.util.Dom.setStyle(this.getEl(),'position','relative');}if(typeof attributes['points']['from']!='undefined'){YAHOO.util.Dom.setXY(this.getEl(),attributes['points']['from']);start=this.getAttribute('points');}else if((start[0]===0||start[1]===0)){YAHOO.util.Dom.setXY(this.getEl(),YAHOO.util.Dom.getXY(this.getEl()));start=this.getAttribute('points');}var i,len;if(typeof attributes['points']['to']!='undefined'){end=translateValues(attributes['points']['to'],this);for(i=0,len=control.length;i<len;++i){control[i]=translateValues(control[i],this);}}else if(typeof attributes['points']['by']!='undefined'){end=[start[0]+attributes['points']['by'][0],start[1]+attributes['points']['by'][1]];for(i=0,len=control.length;i<len;++i){control[i]=[start[0]+control[i][0],start[1]+control[i][1]];}}if(end){translatedPoints=[start];if(control.length>0){translatedPoints=translatedPoints.concat(control);}translatedPoints[translatedPoints.length]=end;}};this._onStart.subscribe(onStart);};YAHOO.util.Scroll=function(el,attributes,duration,method){if(el){YAHOO.util.Anim.call(this,el,attributes,duration,method);}};YAHOO.util.Scroll.prototype=new YAHOO.util.Anim();YAHOO.util.Scroll.prototype.defaultUnits.scroll=' ';YAHOO.util.Scroll.prototype.doMethod=function(attribute,start,end){var val=null;if(attribute=='scroll'){val=[this.method(this.currentFrame,start[0],end[0]-start[0],this.totalFrames),this.method(this.currentFrame,start[1],end[1]-start[1],this.totalFrames)];}else{val=this.method(this.currentFrame,start,end-start,this.totalFrames);}return val;};YAHOO.util.Scroll.prototype.getAttribute=function(attribute){var val=null;var el=this.getEl();if(attribute=='scroll'){val=[el.scrollLeft,el.scrollTop];}else{val=parseFloat(YAHOO.util.Dom.getStyle(el,attribute));}return val;};YAHOO.util.Scroll.prototype.setAttribute=function(attribute,val,unit){var el=this.getEl();if(attribute=='scroll'){el.scrollLeft=val[0];el.scrollTop=val[1];}else{YAHOO.util.Dom.setStyle(el,attribute,val+unit);}};
Index: /branches/features/grailsUpgrade/web-app/js/prototype/builder.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/builder.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/builder.js	(revision 875)
@@ -0,0 +1,136 @@
+// script.aculo.us builder.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Builder = {
+  NODEMAP: {
+    AREA: 'map',
+    CAPTION: 'table',
+    COL: 'table',
+    COLGROUP: 'table',
+    LEGEND: 'fieldset',
+    OPTGROUP: 'select',
+    OPTION: 'select',
+    PARAM: 'object',
+    TBODY: 'table',
+    TD: 'table',
+    TFOOT: 'table',
+    TH: 'table',
+    THEAD: 'table',
+    TR: 'table'
+  },
+  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
+  //       due to a Firefox bug
+  node: function(elementName) {
+    elementName = elementName.toUpperCase();
+    
+    // try innerHTML approach
+    var parentTag = this.NODEMAP[elementName] || 'div';
+    var parentElement = document.createElement(parentTag);
+    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
+    } catch(e) {}
+    var element = parentElement.firstChild || null;
+      
+    // see if browser added wrapping tags
+    if(element && (element.tagName.toUpperCase() != elementName))
+      element = element.getElementsByTagName(elementName)[0];
+    
+    // fallback to createElement approach
+    if(!element) element = document.createElement(elementName);
+    
+    // abort if nothing could be created
+    if(!element) return;
+
+    // attributes (or text)
+    if(arguments[1])
+      if(this._isStringOrNumber(arguments[1]) ||
+        (arguments[1] instanceof Array) ||
+        arguments[1].tagName) {
+          this._children(element, arguments[1]);
+        } else {
+          var attrs = this._attributes(arguments[1]);
+          if(attrs.length) {
+            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
+              parentElement.innerHTML = "<" +elementName + " " +
+                attrs + "></" + elementName + ">";
+            } catch(e) {}
+            element = parentElement.firstChild || null;
+            // workaround firefox 1.0.X bug
+            if(!element) {
+              element = document.createElement(elementName);
+              for(attr in arguments[1]) 
+                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
+            }
+            if(element.tagName.toUpperCase() != elementName)
+              element = parentElement.getElementsByTagName(elementName)[0];
+          }
+        } 
+
+    // text, or array of children
+    if(arguments[2])
+      this._children(element, arguments[2]);
+
+     return element;
+  },
+  _text: function(text) {
+     return document.createTextNode(text);
+  },
+
+  ATTR_MAP: {
+    'className': 'class',
+    'htmlFor': 'for'
+  },
+
+  _attributes: function(attributes) {
+    var attrs = [];
+    for(attribute in attributes)
+      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
+          '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
+    return attrs.join(" ");
+  },
+  _children: function(element, children) {
+    if(children.tagName) {
+      element.appendChild(children);
+      return;
+    }
+    if(typeof children=='object') { // array can hold nodes and text
+      children.flatten().each( function(e) {
+        if(typeof e=='object')
+          element.appendChild(e)
+        else
+          if(Builder._isStringOrNumber(e))
+            element.appendChild(Builder._text(e));
+      });
+    } else
+      if(Builder._isStringOrNumber(children))
+        element.appendChild(Builder._text(children));
+  },
+  _isStringOrNumber: function(param) {
+    return(typeof param=='string' || typeof param=='number');
+  },
+  build: function(html) {
+    var element = this.node('div');
+    $(element).update(html.strip());
+    return element.down();
+  },
+  dump: function(scope) { 
+    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope 
+  
+    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
+      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
+      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
+      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
+      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
+      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
+  
+    tags.each( function(tag){ 
+      scope[tag] = function() { 
+        return Builder.node.apply(Builder, [tag].concat($A(arguments)));  
+      } 
+    });
+  }
+}
Index: /branches/features/grailsUpgrade/web-app/js/prototype/controls.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/controls.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/controls.js	(revision 875)
@@ -0,0 +1,965 @@
+// script.aculo.us controls.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//           (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
+//           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
+// Contributors:
+//  Richard Livsey
+//  Rahul Bhargava
+//  Rob Wills
+// 
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// Autocompleter.Base handles all the autocompletion functionality 
+// that's independent of the data source for autocompletion. This
+// includes drawing the autocompletion menu, observing keyboard
+// and mouse events, and similar.
+//
+// Specific autocompleters need to provide, at the very least, 
+// a getUpdatedChoices function that will be invoked every time
+// the text inside the monitored textbox changes. This method 
+// should get the text for which to provide autocompletion by
+// invoking this.getToken(), NOT by directly accessing
+// this.element.value. This is to allow incremental tokenized
+// autocompletion. Specific auto-completion logic (AJAX, etc)
+// belongs in getUpdatedChoices.
+//
+// Tokenized incremental autocompletion is enabled automatically
+// when an autocompleter is instantiated with the 'tokens' option
+// in the options parameter, e.g.:
+// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
+// will incrementally autocomplete with a comma as the token.
+// Additionally, ',' in the above example can be replaced with
+// a token array, e.g. { tokens: [',', '\n'] } which
+// enables autocompletion on multiple tokens. This is most 
+// useful when one of the tokens is \n (a newline), as it 
+// allows smart autocompletion after linebreaks.
+
+if(typeof Effect == 'undefined')
+  throw("controls.js requires including script.aculo.us' effects.js library");
+
+var Autocompleter = { }
+Autocompleter.Base = Class.create({
+  baseInitialize: function(element, update, options) {
+    element          = $(element)
+    this.element     = element; 
+    this.update      = $(update);  
+    this.hasFocus    = false; 
+    this.changed     = false; 
+    this.active      = false; 
+    this.index       = 0;     
+    this.entryCount  = 0;
+    this.oldElementValue = this.element.value;
+
+    if(this.setOptions)
+      this.setOptions(options);
+    else
+      this.options = options || { };
+
+    this.options.paramName    = this.options.paramName || this.element.name;
+    this.options.tokens       = this.options.tokens || [];
+    this.options.frequency    = this.options.frequency || 0.4;
+    this.options.minChars     = this.options.minChars || 1;
+    this.options.onShow       = this.options.onShow || 
+      function(element, update){ 
+        if(!update.style.position || update.style.position=='absolute') {
+          update.style.position = 'absolute';
+          Position.clone(element, update, {
+            setHeight: false, 
+            offsetTop: element.offsetHeight
+          });
+        }
+        Effect.Appear(update,{duration:0.15});
+      };
+    this.options.onHide = this.options.onHide || 
+      function(element, update){ new Effect.Fade(update,{duration:0.15}) };
+
+    if(typeof(this.options.tokens) == 'string') 
+      this.options.tokens = new Array(this.options.tokens);
+    // Force carriage returns as token delimiters anyway
+    if (!this.options.tokens.include('\n'))
+      this.options.tokens.push('\n');
+
+    this.observer = null;
+    
+    this.element.setAttribute('autocomplete','off');
+
+    Element.hide(this.update);
+
+    Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
+    Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this));
+  },
+
+  show: function() {
+    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
+    if(!this.iefix && 
+      (Prototype.Browser.IE) &&
+      (Element.getStyle(this.update, 'position')=='absolute')) {
+      new Insertion.After(this.update, 
+       '<iframe id="' + this.update.id + '_iefix" '+
+       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
+       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
+      this.iefix = $(this.update.id+'_iefix');
+    }
+    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
+  },
+  
+  fixIEOverlapping: function() {
+    Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
+    this.iefix.style.zIndex = 1;
+    this.update.style.zIndex = 2;
+    Element.show(this.iefix);
+  },
+
+  hide: function() {
+    this.stopIndicator();
+    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
+    if(this.iefix) Element.hide(this.iefix);
+  },
+
+  startIndicator: function() {
+    if(this.options.indicator) Element.show(this.options.indicator);
+  },
+
+  stopIndicator: function() {
+    if(this.options.indicator) Element.hide(this.options.indicator);
+  },
+
+  onKeyPress: function(event) {
+    if(this.active)
+      switch(event.keyCode) {
+       case Event.KEY_TAB:
+       case Event.KEY_RETURN:
+         this.selectEntry();
+         Event.stop(event);
+       case Event.KEY_ESC:
+         this.hide();
+         this.active = false;
+         Event.stop(event);
+         return;
+       case Event.KEY_LEFT:
+       case Event.KEY_RIGHT:
+         return;
+       case Event.KEY_UP:
+         this.markPrevious();
+         this.render();
+         if(Prototype.Browser.WebKit) Event.stop(event);
+         return;
+       case Event.KEY_DOWN:
+         this.markNext();
+         this.render();
+         if(Prototype.Browser.WebKit) Event.stop(event);
+         return;
+      }
+     else 
+       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
+         (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
+
+    this.changed = true;
+    this.hasFocus = true;
+
+    if(this.observer) clearTimeout(this.observer);
+      this.observer = 
+        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
+  },
+
+  activate: function() {
+    this.changed = false;
+    this.hasFocus = true;
+    this.getUpdatedChoices();
+  },
+
+  onHover: function(event) {
+    var element = Event.findElement(event, 'LI');
+    if(this.index != element.autocompleteIndex) 
+    {
+        this.index = element.autocompleteIndex;
+        this.render();
+    }
+    Event.stop(event);
+  },
+  
+  onClick: function(event) {
+    var element = Event.findElement(event, 'LI');
+    this.index = element.autocompleteIndex;
+    this.selectEntry();
+    this.hide();
+  },
+  
+  onBlur: function(event) {
+    // needed to make click events working
+    setTimeout(this.hide.bind(this), 250);
+    this.hasFocus = false;
+    this.active = false;     
+  }, 
+  
+  render: function() {
+    if(this.entryCount > 0) {
+      for (var i = 0; i < this.entryCount; i++)
+        this.index==i ? 
+          Element.addClassName(this.getEntry(i),"selected") : 
+          Element.removeClassName(this.getEntry(i),"selected");
+      if(this.hasFocus) { 
+        this.show();
+        this.active = true;
+      }
+    } else {
+      this.active = false;
+      this.hide();
+    }
+  },
+  
+  markPrevious: function() {
+    if(this.index > 0) this.index--
+      else this.index = this.entryCount-1;
+    this.getEntry(this.index).scrollIntoView(true);
+  },
+  
+  markNext: function() {
+    if(this.index < this.entryCount-1) this.index++
+      else this.index = 0;
+    this.getEntry(this.index).scrollIntoView(false);
+  },
+  
+  getEntry: function(index) {
+    return this.update.firstChild.childNodes[index];
+  },
+  
+  getCurrentEntry: function() {
+    return this.getEntry(this.index);
+  },
+  
+  selectEntry: function() {
+    this.active = false;
+    this.updateElement(this.getCurrentEntry());
+  },
+
+  updateElement: function(selectedElement) {
+    if (this.options.updateElement) {
+      this.options.updateElement(selectedElement);
+      return;
+    }
+    var value = '';
+    if (this.options.select) {
+      var nodes = $(selectedElement).select('.' + this.options.select) || [];
+      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
+    } else
+      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
+    
+    var bounds = this.getTokenBounds();
+    if (bounds[0] != -1) {
+      var newValue = this.element.value.substr(0, bounds[0]);
+      var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
+      if (whitespace)
+        newValue += whitespace[0];
+      this.element.value = newValue + value + this.element.value.substr(bounds[1]);
+    } else {
+      this.element.value = value;
+    }
+    this.oldElementValue = this.element.value;
+    this.element.focus();
+    
+    if (this.options.afterUpdateElement)
+      this.options.afterUpdateElement(this.element, selectedElement);
+  },
+
+  updateChoices: function(choices) {
+    if(!this.changed && this.hasFocus) {
+      this.update.innerHTML = choices;
+      Element.cleanWhitespace(this.update);
+      Element.cleanWhitespace(this.update.down());
+
+      if(this.update.firstChild && this.update.down().childNodes) {
+        this.entryCount = 
+          this.update.down().childNodes.length;
+        for (var i = 0; i < this.entryCount; i++) {
+          var entry = this.getEntry(i);
+          entry.autocompleteIndex = i;
+          this.addObservers(entry);
+        }
+      } else { 
+        this.entryCount = 0;
+      }
+
+      this.stopIndicator();
+      this.index = 0;
+      
+      if(this.entryCount==1 && this.options.autoSelect) {
+        this.selectEntry();
+        this.hide();
+      } else {
+        this.render();
+      }
+    }
+  },
+
+  addObservers: function(element) {
+    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
+    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
+  },
+
+  onObserverEvent: function() {
+    this.changed = false;   
+    this.tokenBounds = null;
+    if(this.getToken().length>=this.options.minChars) {
+      this.getUpdatedChoices();
+    } else {
+      this.active = false;
+      this.hide();
+    }
+    this.oldElementValue = this.element.value;
+  },
+
+  getToken: function() {
+    var bounds = this.getTokenBounds();
+    return this.element.value.substring(bounds[0], bounds[1]).strip();
+  },
+
+  getTokenBounds: function() {
+    if (null != this.tokenBounds) return this.tokenBounds;
+    var value = this.element.value;
+    if (value.strip().empty()) return [-1, 0];
+    var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
+    var offset = (diff == this.oldElementValue.length ? 1 : 0);
+    var prevTokenPos = -1, nextTokenPos = value.length;
+    var tp;
+    for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
+      tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
+      if (tp > prevTokenPos) prevTokenPos = tp;
+      tp = value.indexOf(this.options.tokens[index], diff + offset);
+      if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
+    }
+    return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
+  }
+});
+
+Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
+  var boundary = Math.min(newS.length, oldS.length);
+  for (var index = 0; index < boundary; ++index)
+    if (newS[index] != oldS[index])
+      return index;
+  return boundary;
+};
+
+Ajax.Autocompleter = Class.create(Autocompleter.Base, {
+  initialize: function(element, update, url, options) {
+    this.baseInitialize(element, update, options);
+    this.options.asynchronous  = true;
+    this.options.onComplete    = this.onComplete.bind(this);
+    this.options.defaultParams = this.options.parameters || null;
+    this.url                   = url;
+  },
+
+  getUpdatedChoices: function() {
+    this.startIndicator();
+    
+    var entry = encodeURIComponent(this.options.paramName) + '=' + 
+      encodeURIComponent(this.getToken());
+
+    this.options.parameters = this.options.callback ?
+      this.options.callback(this.element, entry) : entry;
+
+    if(this.options.defaultParams) 
+      this.options.parameters += '&' + this.options.defaultParams;
+    
+    new Ajax.Request(this.url, this.options);
+  },
+
+  onComplete: function(request) {
+    this.updateChoices(request.responseText);
+  }
+});
+
+// The local array autocompleter. Used when you'd prefer to
+// inject an array of autocompletion options into the page, rather
+// than sending out Ajax queries, which can be quite slow sometimes.
+//
+// The constructor takes four parameters. The first two are, as usual,
+// the id of the monitored textbox, and id of the autocompletion menu.
+// The third is the array you want to autocomplete from, and the fourth
+// is the options block.
+//
+// Extra local autocompletion options:
+// - choices - How many autocompletion choices to offer
+//
+// - partialSearch - If false, the autocompleter will match entered
+//                    text only at the beginning of strings in the 
+//                    autocomplete array. Defaults to true, which will
+//                    match text at the beginning of any *word* in the
+//                    strings in the autocomplete array. If you want to
+//                    search anywhere in the string, additionally set
+//                    the option fullSearch to true (default: off).
+//
+// - fullSsearch - Search anywhere in autocomplete array strings.
+//
+// - partialChars - How many characters to enter before triggering
+//                   a partial match (unlike minChars, which defines
+//                   how many characters are required to do any match
+//                   at all). Defaults to 2.
+//
+// - ignoreCase - Whether to ignore case when autocompleting.
+//                 Defaults to true.
+//
+// It's possible to pass in a custom function as the 'selector' 
+// option, if you prefer to write your own autocompletion logic.
+// In that case, the other options above will not apply unless
+// you support them.
+
+Autocompleter.Local = Class.create(Autocompleter.Base, {
+  initialize: function(element, update, array, options) {
+    this.baseInitialize(element, update, options);
+    this.options.array = array;
+  },
+
+  getUpdatedChoices: function() {
+    this.updateChoices(this.options.selector(this));
+  },
+
+  setOptions: function(options) {
+    this.options = Object.extend({
+      choices: 10,
+      partialSearch: true,
+      partialChars: 2,
+      ignoreCase: true,
+      fullSearch: false,
+      selector: function(instance) {
+        var ret       = []; // Beginning matches
+        var partial   = []; // Inside matches
+        var entry     = instance.getToken();
+        var count     = 0;
+
+        for (var i = 0; i < instance.options.array.length &&  
+          ret.length < instance.options.choices ; i++) { 
+
+          var elem = instance.options.array[i];
+          var foundPos = instance.options.ignoreCase ? 
+            elem.toLowerCase().indexOf(entry.toLowerCase()) : 
+            elem.indexOf(entry);
+
+          while (foundPos != -1) {
+            if (foundPos == 0 && elem.length != entry.length) { 
+              ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + 
+                elem.substr(entry.length) + "</li>");
+              break;
+            } else if (entry.length >= instance.options.partialChars && 
+              instance.options.partialSearch && foundPos != -1) {
+              if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
+                partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
+                  elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
+                  foundPos + entry.length) + "</li>");
+                break;
+              }
+            }
+
+            foundPos = instance.options.ignoreCase ? 
+              elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : 
+              elem.indexOf(entry, foundPos + 1);
+
+          }
+        }
+        if (partial.length)
+          ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
+        return "<ul>" + ret.join('') + "</ul>";
+      }
+    }, options || { });
+  }
+});
+
+// AJAX in-place editor and collection editor
+// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
+
+// Use this if you notice weird scrolling problems on some browsers,
+// the DOM might be a bit confused when this gets called so do this
+// waits 1 ms (with setTimeout) until it does the activation
+Field.scrollFreeActivate = function(field) {
+  setTimeout(function() {
+    Field.activate(field);
+  }, 1);
+}
+
+Ajax.InPlaceEditor = Class.create({
+  initialize: function(element, url, options) {
+    this.url = url;
+    this.element = element = $(element);
+    this.prepareOptions();
+    this._controls = { };
+    arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
+    Object.extend(this.options, options || { });
+    if (!this.options.formId && this.element.id) {
+      this.options.formId = this.element.id + '-inplaceeditor';
+      if ($(this.options.formId))
+        this.options.formId = '';
+    }
+    if (this.options.externalControl)
+      this.options.externalControl = $(this.options.externalControl);
+    if (!this.options.externalControl)
+      this.options.externalControlOnly = false;
+    this._originalBackground = this.element.getStyle('background-color') || 'transparent';
+    this.element.title = this.options.clickToEditText;
+    this._boundCancelHandler = this.handleFormCancellation.bind(this);
+    this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
+    this._boundFailureHandler = this.handleAJAXFailure.bind(this);
+    this._boundSubmitHandler = this.handleFormSubmission.bind(this);
+    this._boundWrapperHandler = this.wrapUp.bind(this);
+    this.registerListeners();
+  },
+  checkForEscapeOrReturn: function(e) {
+    if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
+    if (Event.KEY_ESC == e.keyCode)
+      this.handleFormCancellation(e);
+    else if (Event.KEY_RETURN == e.keyCode)
+      this.handleFormSubmission(e);
+  },
+  createControl: function(mode, handler, extraClasses) {
+    var control = this.options[mode + 'Control'];
+    var text = this.options[mode + 'Text'];
+    if ('button' == control) {
+      var btn = document.createElement('input');
+      btn.type = 'submit';
+      btn.value = text;
+      btn.className = 'editor_' + mode + '_button';
+      if ('cancel' == mode)
+        btn.onclick = this._boundCancelHandler;
+      this._form.appendChild(btn);
+      this._controls[mode] = btn;
+    } else if ('link' == control) {
+      var link = document.createElement('a');
+      link.href = '#';
+      link.appendChild(document.createTextNode(text));
+      link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
+      link.className = 'editor_' + mode + '_link';
+      if (extraClasses)
+        link.className += ' ' + extraClasses;
+      this._form.appendChild(link);
+      this._controls[mode] = link;
+    }
+  },
+  createEditField: function() {
+    var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
+    var fld;
+    if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
+      fld = document.createElement('input');
+      fld.type = 'text';
+      var size = this.options.size || this.options.cols || 0;
+      if (0 < size) fld.size = size;
+    } else {
+      fld = document.createElement('textarea');
+      fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
+      fld.cols = this.options.cols || 40;
+    }
+    fld.name = this.options.paramName;
+    fld.value = text; // No HTML breaks conversion anymore
+    fld.className = 'editor_field';
+    if (this.options.submitOnBlur)
+      fld.onblur = this._boundSubmitHandler;
+    this._controls.editor = fld;
+    if (this.options.loadTextURL)
+      this.loadExternalText();
+    this._form.appendChild(this._controls.editor);
+  },
+  createForm: function() {
+    var ipe = this;
+    function addText(mode, condition) {
+      var text = ipe.options['text' + mode + 'Controls'];
+      if (!text || condition === false) return;
+      ipe._form.appendChild(document.createTextNode(text));
+    };
+    this._form = $(document.createElement('form'));
+    this._form.id = this.options.formId;
+    this._form.addClassName(this.options.formClassName);
+    this._form.onsubmit = this._boundSubmitHandler;
+    this.createEditField();
+    if ('textarea' == this._controls.editor.tagName.toLowerCase())
+      this._form.appendChild(document.createElement('br'));
+    if (this.options.onFormCustomization)
+      this.options.onFormCustomization(this, this._form);
+    addText('Before', this.options.okControl || this.options.cancelControl);
+    this.createControl('ok', this._boundSubmitHandler);
+    addText('Between', this.options.okControl && this.options.cancelControl);
+    this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
+    addText('After', this.options.okControl || this.options.cancelControl);
+  },
+  destroy: function() {
+    if (this._oldInnerHTML)
+      this.element.innerHTML = this._oldInnerHTML;
+    this.leaveEditMode();
+    this.unregisterListeners();
+  },
+  enterEditMode: function(e) {
+    if (this._saving || this._editing) return;
+    this._editing = true;
+    this.triggerCallback('onEnterEditMode');
+    if (this.options.externalControl)
+      this.options.externalControl.hide();
+    this.element.hide();
+    this.createForm();
+    this.element.parentNode.insertBefore(this._form, this.element);
+    if (!this.options.loadTextURL)
+      this.postProcessEditField();
+    if (e) Event.stop(e);
+  },
+  enterHover: function(e) {
+    if (this.options.hoverClassName)
+      this.element.addClassName(this.options.hoverClassName);
+    if (this._saving) return;
+    this.triggerCallback('onEnterHover');
+  },
+  getText: function() {
+    return this.element.innerHTML;
+  },
+  handleAJAXFailure: function(transport) {
+    this.triggerCallback('onFailure', transport);
+    if (this._oldInnerHTML) {
+      this.element.innerHTML = this._oldInnerHTML;
+      this._oldInnerHTML = null;
+    }
+  },
+  handleFormCancellation: function(e) {
+    this.wrapUp();
+    if (e) Event.stop(e);
+  },
+  handleFormSubmission: function(e) {
+    var form = this._form;
+    var value = $F(this._controls.editor);
+    this.prepareSubmission();
+    var params = this.options.callback(form, value) || '';
+    if (Object.isString(params))
+      params = params.toQueryParams();
+    params.editorId = this.element.id;
+    if (this.options.htmlResponse) {
+      var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
+      Object.extend(options, {
+        parameters: params,
+        onComplete: this._boundWrapperHandler,
+        onFailure: this._boundFailureHandler
+      });
+      new Ajax.Updater({ success: this.element }, this.url, options);
+    } else {
+      var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+      Object.extend(options, {
+        parameters: params,
+        onComplete: this._boundWrapperHandler,
+        onFailure: this._boundFailureHandler
+      });
+      new Ajax.Request(this.url, options);
+    }
+    if (e) Event.stop(e);
+  },
+  leaveEditMode: function() {
+    this.element.removeClassName(this.options.savingClassName);
+    this.removeForm();
+    this.leaveHover();
+    this.element.style.backgroundColor = this._originalBackground;
+    this.element.show();
+    if (this.options.externalControl)
+      this.options.externalControl.show();
+    this._saving = false;
+    this._editing = false;
+    this._oldInnerHTML = null;
+    this.triggerCallback('onLeaveEditMode');
+  },
+  leaveHover: function(e) {
+    if (this.options.hoverClassName)
+      this.element.removeClassName(this.options.hoverClassName);
+    if (this._saving) return;
+    this.triggerCallback('onLeaveHover');
+  },
+  loadExternalText: function() {
+    this._form.addClassName(this.options.loadingClassName);
+    this._controls.editor.disabled = true;
+    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+    Object.extend(options, {
+      parameters: 'editorId=' + encodeURIComponent(this.element.id),
+      onComplete: Prototype.emptyFunction,
+      onSuccess: function(transport) {
+        this._form.removeClassName(this.options.loadingClassName);
+        var text = transport.responseText;
+        if (this.options.stripLoadedTextTags)
+          text = text.stripTags();
+        this._controls.editor.value = text;
+        this._controls.editor.disabled = false;
+        this.postProcessEditField();
+      }.bind(this),
+      onFailure: this._boundFailureHandler
+    });
+    new Ajax.Request(this.options.loadTextURL, options);
+  },
+  postProcessEditField: function() {
+    var fpc = this.options.fieldPostCreation;
+    if (fpc)
+      $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
+  },
+  prepareOptions: function() {
+    this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
+    Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
+    [this._extraDefaultOptions].flatten().compact().each(function(defs) {
+      Object.extend(this.options, defs);
+    }.bind(this));
+  },
+  prepareSubmission: function() {
+    this._saving = true;
+    this.removeForm();
+    this.leaveHover();
+    this.showSaving();
+  },
+  registerListeners: function() {
+    this._listeners = { };
+    var listener;
+    $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
+      listener = this[pair.value].bind(this);
+      this._listeners[pair.key] = listener;
+      if (!this.options.externalControlOnly)
+        this.element.observe(pair.key, listener);
+      if (this.options.externalControl)
+        this.options.externalControl.observe(pair.key, listener);
+    }.bind(this));
+  },
+  removeForm: function() {
+    if (!this._form) return;
+    this._form.remove();
+    this._form = null;
+    this._controls = { };
+  },
+  showSaving: function() {
+    this._oldInnerHTML = this.element.innerHTML;
+    this.element.innerHTML = this.options.savingText;
+    this.element.addClassName(this.options.savingClassName);
+    this.element.style.backgroundColor = this._originalBackground;
+    this.element.show();
+  },
+  triggerCallback: function(cbName, arg) {
+    if ('function' == typeof this.options[cbName]) {
+      this.options[cbName](this, arg);
+    }
+  },
+  unregisterListeners: function() {
+    $H(this._listeners).each(function(pair) {
+      if (!this.options.externalControlOnly)
+        this.element.stopObserving(pair.key, pair.value);
+      if (this.options.externalControl)
+        this.options.externalControl.stopObserving(pair.key, pair.value);
+    }.bind(this));
+  },
+  wrapUp: function(transport) {
+    this.leaveEditMode();
+    // Can't use triggerCallback due to backward compatibility: requires
+    // binding + direct element
+    this._boundComplete(transport, this.element);
+  }
+});
+
+Object.extend(Ajax.InPlaceEditor.prototype, {
+  dispose: Ajax.InPlaceEditor.prototype.destroy
+});
+
+Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
+  initialize: function($super, element, url, options) {
+    this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
+    $super(element, url, options);
+  },
+
+  createEditField: function() {
+    var list = document.createElement('select');
+    list.name = this.options.paramName;
+    list.size = 1;
+    this._controls.editor = list;
+    this._collection = this.options.collection || [];
+    if (this.options.loadCollectionURL)
+      this.loadCollection();
+    else
+      this.checkForExternalText();
+    this._form.appendChild(this._controls.editor);
+  },
+
+  loadCollection: function() {
+    this._form.addClassName(this.options.loadingClassName);
+    this.showLoadingText(this.options.loadingCollectionText);
+    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+    Object.extend(options, {
+      parameters: 'editorId=' + encodeURIComponent(this.element.id),
+      onComplete: Prototype.emptyFunction,
+      onSuccess: function(transport) {
+        var js = transport.responseText.strip();
+        if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
+          throw 'Server returned an invalid collection representation.';
+        this._collection = eval(js);
+        this.checkForExternalText();
+      }.bind(this),
+      onFailure: this.onFailure
+    });
+    new Ajax.Request(this.options.loadCollectionURL, options);
+  },
+
+  showLoadingText: function(text) {
+    this._controls.editor.disabled = true;
+    var tempOption = this._controls.editor.firstChild;
+    if (!tempOption) {
+      tempOption = document.createElement('option');
+      tempOption.value = '';
+      this._controls.editor.appendChild(tempOption);
+      tempOption.selected = true;
+    }
+    tempOption.update((text || '').stripScripts().stripTags());
+  },
+
+  checkForExternalText: function() {
+    this._text = this.getText();
+    if (this.options.loadTextURL)
+      this.loadExternalText();
+    else
+      this.buildOptionList();
+  },
+
+  loadExternalText: function() {
+    this.showLoadingText(this.options.loadingText);
+    var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
+    Object.extend(options, {
+      parameters: 'editorId=' + encodeURIComponent(this.element.id),
+      onComplete: Prototype.emptyFunction,
+      onSuccess: function(transport) {
+        this._text = transport.responseText.strip();
+        this.buildOptionList();
+      }.bind(this),
+      onFailure: this.onFailure
+    });
+    new Ajax.Request(this.options.loadTextURL, options);
+  },
+
+  buildOptionList: function() {
+    this._form.removeClassName(this.options.loadingClassName);
+    this._collection = this._collection.map(function(entry) {
+      return 2 === entry.length ? entry : [entry, entry].flatten();
+    });
+    var marker = ('value' in this.options) ? this.options.value : this._text;
+    var textFound = this._collection.any(function(entry) {
+      return entry[0] == marker;
+    }.bind(this));
+    this._controls.editor.update('');
+    var option;
+    this._collection.each(function(entry, index) {
+      option = document.createElement('option');
+      option.value = entry[0];
+      option.selected = textFound ? entry[0] == marker : 0 == index;
+      option.appendChild(document.createTextNode(entry[1]));
+      this._controls.editor.appendChild(option);
+    }.bind(this));
+    this._controls.editor.disabled = false;
+    Field.scrollFreeActivate(this._controls.editor);
+  }
+});
+
+//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
+//**** This only  exists for a while,  in order to  let ****
+//**** users adapt to  the new API.  Read up on the new ****
+//**** API and convert your code to it ASAP!            ****
+
+Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
+  if (!options) return;
+  function fallback(name, expr) {
+    if (name in options || expr === undefined) return;
+    options[name] = expr;
+  };
+  fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
+    options.cancelLink == options.cancelButton == false ? false : undefined)));
+  fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
+    options.okLink == options.okButton == false ? false : undefined)));
+  fallback('highlightColor', options.highlightcolor);
+  fallback('highlightEndColor', options.highlightendcolor);
+};
+
+Object.extend(Ajax.InPlaceEditor, {
+  DefaultOptions: {
+    ajaxOptions: { },
+    autoRows: 3,                                // Use when multi-line w/ rows == 1
+    cancelControl: 'link',                      // 'link'|'button'|false
+    cancelText: 'cancel',
+    clickToEditText: 'Click to edit',
+    externalControl: null,                      // id|elt
+    externalControlOnly: false,
+    fieldPostCreation: 'activate',              // 'activate'|'focus'|false
+    formClassName: 'inplaceeditor-form',
+    formId: null,                               // id|elt
+    highlightColor: '#ffff99',
+    highlightEndColor: '#ffffff',
+    hoverClassName: '',
+    htmlResponse: true,
+    loadingClassName: 'inplaceeditor-loading',
+    loadingText: 'Loading...',
+    okControl: 'button',                        // 'link'|'button'|false
+    okText: 'ok',
+    paramName: 'value',
+    rows: 1,                                    // If 1 and multi-line, uses autoRows
+    savingClassName: 'inplaceeditor-saving',
+    savingText: 'Saving...',
+    size: 0,
+    stripLoadedTextTags: false,
+    submitOnBlur: false,
+    textAfterControls: '',
+    textBeforeControls: '',
+    textBetweenControls: ''
+  },
+  DefaultCallbacks: {
+    callback: function(form) {
+      return Form.serialize(form);
+    },
+    onComplete: function(transport, element) {
+      // For backward compatibility, this one is bound to the IPE, and passes
+      // the element directly.  It was too often customized, so we don't break it.
+      new Effect.Highlight(element, {
+        startcolor: this.options.highlightColor, keepBackgroundImage: true });
+    },
+    onEnterEditMode: null,
+    onEnterHover: function(ipe) {
+      ipe.element.style.backgroundColor = ipe.options.highlightColor;
+      if (ipe._effect)
+        ipe._effect.cancel();
+    },
+    onFailure: function(transport, ipe) {
+      alert('Error communication with the server: ' + transport.responseText.stripTags());
+    },
+    onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
+    onLeaveEditMode: null,
+    onLeaveHover: function(ipe) {
+      ipe._effect = new Effect.Highlight(ipe.element, {
+        startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
+        restorecolor: ipe._originalBackground, keepBackgroundImage: true
+      });
+    }
+  },
+  Listeners: {
+    click: 'enterEditMode',
+    keydown: 'checkForEscapeOrReturn',
+    mouseover: 'enterHover',
+    mouseout: 'leaveHover'
+  }
+});
+
+Ajax.InPlaceCollectionEditor.DefaultOptions = {
+  loadingCollectionText: 'Loading options...'
+};
+
+// Delayed observer, like Form.Element.Observer, 
+// but waits for delay after last key input
+// Ideal for live-search fields
+
+Form.Element.DelayedObserver = Class.create({
+  initialize: function(element, delay, callback) {
+    this.delay     = delay || 0.5;
+    this.element   = $(element);
+    this.callback  = callback;
+    this.timer     = null;
+    this.lastValue = $F(this.element); 
+    Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
+  },
+  delayedListener: function(event) {
+    if(this.lastValue == $F(this.element)) return;
+    if(this.timer) clearTimeout(this.timer);
+    this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
+    this.lastValue = $F(this.element);
+  },
+  onTimerEvent: function() {
+    this.timer = null;
+    this.callback(this.element, $F(this.element));
+  }
+});
Index: /branches/features/grailsUpgrade/web-app/js/prototype/dragdrop.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/dragdrop.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/dragdrop.js	(revision 875)
@@ -0,0 +1,974 @@
+// script.aculo.us dragdrop.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//           (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
+// 
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if(Object.isUndefined(Effect))
+  throw("dragdrop.js requires including script.aculo.us' effects.js library");
+
+var Droppables = {
+  drops: [],
+
+  remove: function(element) {
+    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
+  },
+
+  add: function(element) {
+    element = $(element);
+    var options = Object.extend({
+      greedy:     true,
+      hoverclass: null,
+      tree:       false
+    }, arguments[1] || { });
+
+    // cache containers
+    if(options.containment) {
+      options._containers = [];
+      var containment = options.containment;
+      if(Object.isArray(containment)) {
+        containment.each( function(c) { options._containers.push($(c)) });
+      } else {
+        options._containers.push($(containment));
+      }
+    }
+    
+    if(options.accept) options.accept = [options.accept].flatten();
+
+    Element.makePositioned(element); // fix IE
+    options.element = element;
+
+    this.drops.push(options);
+  },
+  
+  findDeepestChild: function(drops) {
+    deepest = drops[0];
+      
+    for (i = 1; i < drops.length; ++i)
+      if (Element.isParent(drops[i].element, deepest.element))
+        deepest = drops[i];
+    
+    return deepest;
+  },
+
+  isContained: function(element, drop) {
+    var containmentNode;
+    if(drop.tree) {
+      containmentNode = element.treeNode; 
+    } else {
+      containmentNode = element.parentNode;
+    }
+    return drop._containers.detect(function(c) { return containmentNode == c });
+  },
+  
+  isAffected: function(point, element, drop) {
+    return (
+      (drop.element!=element) &&
+      ((!drop._containers) ||
+        this.isContained(element, drop)) &&
+      ((!drop.accept) ||
+        (Element.classNames(element).detect( 
+          function(v) { return drop.accept.include(v) } ) )) &&
+      Position.within(drop.element, point[0], point[1]) );
+  },
+
+  deactivate: function(drop) {
+    if(drop.hoverclass)
+      Element.removeClassName(drop.element, drop.hoverclass);
+    this.last_active = null;
+  },
+
+  activate: function(drop) {
+    if(drop.hoverclass)
+      Element.addClassName(drop.element, drop.hoverclass);
+    this.last_active = drop;
+  },
+
+  show: function(point, element) {
+    if(!this.drops.length) return;
+    var drop, affected = [];
+    
+    this.drops.each( function(drop) {
+      if(Droppables.isAffected(point, element, drop))
+        affected.push(drop);
+    });
+        
+    if(affected.length>0)
+      drop = Droppables.findDeepestChild(affected);
+
+    if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
+    if (drop) {
+      Position.within(drop.element, point[0], point[1]);
+      if(drop.onHover)
+        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
+      
+      if (drop != this.last_active) Droppables.activate(drop);
+    }
+  },
+
+  fire: function(event, element) {
+    if(!this.last_active) return;
+    Position.prepare();
+
+    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
+      if (this.last_active.onDrop) {
+        this.last_active.onDrop(element, this.last_active.element, event); 
+        return true; 
+      }
+  },
+
+  reset: function() {
+    if(this.last_active)
+      this.deactivate(this.last_active);
+  }
+}
+
+var Draggables = {
+  drags: [],
+  observers: [],
+  
+  register: function(draggable) {
+    if(this.drags.length == 0) {
+      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
+      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
+      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
+      
+      Event.observe(document, "mouseup", this.eventMouseUp);
+      Event.observe(document, "mousemove", this.eventMouseMove);
+      Event.observe(document, "keypress", this.eventKeypress);
+    }
+    this.drags.push(draggable);
+  },
+  
+  unregister: function(draggable) {
+    this.drags = this.drags.reject(function(d) { return d==draggable });
+    if(this.drags.length == 0) {
+      Event.stopObserving(document, "mouseup", this.eventMouseUp);
+      Event.stopObserving(document, "mousemove", this.eventMouseMove);
+      Event.stopObserving(document, "keypress", this.eventKeypress);
+    }
+  },
+  
+  activate: function(draggable) {
+    if(draggable.options.delay) { 
+      this._timeout = setTimeout(function() { 
+        Draggables._timeout = null; 
+        window.focus(); 
+        Draggables.activeDraggable = draggable; 
+      }.bind(this), draggable.options.delay); 
+    } else {
+      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
+      this.activeDraggable = draggable;
+    }
+  },
+  
+  deactivate: function() {
+    this.activeDraggable = null;
+  },
+  
+  updateDrag: function(event) {
+    if(!this.activeDraggable) return;
+    var pointer = [Event.pointerX(event), Event.pointerY(event)];
+    // Mozilla-based browsers fire successive mousemove events with
+    // the same coordinates, prevent needless redrawing (moz bug?)
+    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
+    this._lastPointer = pointer;
+    
+    this.activeDraggable.updateDrag(event, pointer);
+  },
+  
+  endDrag: function(event) {
+    if(this._timeout) { 
+      clearTimeout(this._timeout); 
+      this._timeout = null; 
+    }
+    if(!this.activeDraggable) return;
+    this._lastPointer = null;
+    this.activeDraggable.endDrag(event);
+    this.activeDraggable = null;
+  },
+  
+  keyPress: function(event) {
+    if(this.activeDraggable)
+      this.activeDraggable.keyPress(event);
+  },
+  
+  addObserver: function(observer) {
+    this.observers.push(observer);
+    this._cacheObserverCallbacks();
+  },
+  
+  removeObserver: function(element) {  // element instead of observer fixes mem leaks
+    this.observers = this.observers.reject( function(o) { return o.element==element });
+    this._cacheObserverCallbacks();
+  },
+  
+  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
+    if(this[eventName+'Count'] > 0)
+      this.observers.each( function(o) {
+        if(o[eventName]) o[eventName](eventName, draggable, event);
+      });
+    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
+  },
+  
+  _cacheObserverCallbacks: function() {
+    ['onStart','onEnd','onDrag'].each( function(eventName) {
+      Draggables[eventName+'Count'] = Draggables.observers.select(
+        function(o) { return o[eventName]; }
+      ).length;
+    });
+  }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Draggable = Class.create({
+  initialize: function(element) {
+    var defaults = {
+      handle: false,
+      reverteffect: function(element, top_offset, left_offset) {
+        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
+        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
+          queue: {scope:'_draggable', position:'end'}
+        });
+      },
+      endeffect: function(element) {
+        var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
+        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
+          queue: {scope:'_draggable', position:'end'},
+          afterFinish: function(){ 
+            Draggable._dragging[element] = false 
+          }
+        }); 
+      },
+      zindex: 1000,
+      revert: false,
+      quiet: false,
+      scroll: false,
+      scrollSensitivity: 20,
+      scrollSpeed: 15,
+      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
+      delay: 0
+    };
+    
+    if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
+      Object.extend(defaults, {
+        starteffect: function(element) {
+          element._opacity = Element.getOpacity(element);
+          Draggable._dragging[element] = true;
+          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
+        }
+      });
+    
+    var options = Object.extend(defaults, arguments[1] || { });
+
+    this.element = $(element);
+    
+    if(options.handle && Object.isString(options.handle))
+      this.handle = this.element.down('.'+options.handle, 0);
+    
+    if(!this.handle) this.handle = $(options.handle);
+    if(!this.handle) this.handle = this.element;
+    
+    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+      options.scroll = $(options.scroll);
+      this._isScrollChild = Element.childOf(this.element, options.scroll);
+    }
+
+    Element.makePositioned(this.element); // fix IE    
+
+    this.options  = options;
+    this.dragging = false;   
+
+    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+    Event.observe(this.handle, "mousedown", this.eventMouseDown);
+    
+    Draggables.register(this);
+  },
+  
+  destroy: function() {
+    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
+    Draggables.unregister(this);
+  },
+  
+  currentDelta: function() {
+    return([
+      parseInt(Element.getStyle(this.element,'left') || '0'),
+      parseInt(Element.getStyle(this.element,'top') || '0')]);
+  },
+  
+  initDrag: function(event) {
+    if(!Object.isUndefined(Draggable._dragging[this.element]) &&
+      Draggable._dragging[this.element]) return;
+    if(Event.isLeftClick(event)) {    
+      // abort on form elements, fixes a Firefox issue
+      var src = Event.element(event);
+      if((tag_name = src.tagName.toUpperCase()) && (
+        tag_name=='INPUT' ||
+        tag_name=='SELECT' ||
+        tag_name=='OPTION' ||
+        tag_name=='BUTTON' ||
+        tag_name=='TEXTAREA')) return;
+        
+      var pointer = [Event.pointerX(event), Event.pointerY(event)];
+      var pos     = Position.cumulativeOffset(this.element);
+      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
+      
+      Draggables.activate(this);
+      Event.stop(event);
+    }
+  },
+  
+  startDrag: function(event) {
+    this.dragging = true;
+    if(!this.delta)
+      this.delta = this.currentDelta();
+    
+    if(this.options.zindex) {
+      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
+      this.element.style.zIndex = this.options.zindex;
+    }
+    
+    if(this.options.ghosting) {
+      this._clone = this.element.cloneNode(true);
+      this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
+      if (!this.element._originallyAbsolute)
+        Position.absolutize(this.element);
+      this.element.parentNode.insertBefore(this._clone, this.element);
+    }
+    
+    if(this.options.scroll) {
+      if (this.options.scroll == window) {
+        var where = this._getWindowScroll(this.options.scroll);
+        this.originalScrollLeft = where.left;
+        this.originalScrollTop = where.top;
+      } else {
+        this.originalScrollLeft = this.options.scroll.scrollLeft;
+        this.originalScrollTop = this.options.scroll.scrollTop;
+      }
+    }
+    
+    Draggables.notify('onStart', this, event);
+        
+    if(this.options.starteffect) this.options.starteffect(this.element);
+  },
+  
+  updateDrag: function(event, pointer) {
+    if(!this.dragging) this.startDrag(event);
+    
+    if(!this.options.quiet){
+      Position.prepare();
+      Droppables.show(pointer, this.element);
+    }
+    
+    Draggables.notify('onDrag', this, event);
+    
+    this.draw(pointer);
+    if(this.options.change) this.options.change(this);
+    
+    if(this.options.scroll) {
+      this.stopScrolling();
+      
+      var p;
+      if (this.options.scroll == window) {
+        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
+      } else {
+        p = Position.page(this.options.scroll);
+        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
+        p[1] += this.options.scroll.scrollTop + Position.deltaY;
+        p.push(p[0]+this.options.scroll.offsetWidth);
+        p.push(p[1]+this.options.scroll.offsetHeight);
+      }
+      var speed = [0,0];
+      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
+      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
+      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
+      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
+      this.startScrolling(speed);
+    }
+    
+    // fix AppleWebKit rendering
+    if(Prototype.Browser.WebKit) window.scrollBy(0,0);
+    
+    Event.stop(event);
+  },
+  
+  finishDrag: function(event, success) {
+    this.dragging = false;
+    
+    if(this.options.quiet){
+      Position.prepare();
+      var pointer = [Event.pointerX(event), Event.pointerY(event)];
+      Droppables.show(pointer, this.element);
+    }
+
+    if(this.options.ghosting) {
+      if (!this.element._originallyAbsolute)
+        Position.relativize(this.element);
+      delete this.element._originallyAbsolute;
+      Element.remove(this._clone);
+      this._clone = null;
+    }
+
+    var dropped = false; 
+    if(success) { 
+      dropped = Droppables.fire(event, this.element); 
+      if (!dropped) dropped = false; 
+    }
+    if(dropped && this.options.onDropped) this.options.onDropped(this.element);
+    Draggables.notify('onEnd', this, event);
+
+    var revert = this.options.revert;
+    if(revert && Object.isFunction(revert)) revert = revert(this.element);
+    
+    var d = this.currentDelta();
+    if(revert && this.options.reverteffect) {
+      if (dropped == 0 || revert != 'failure')
+        this.options.reverteffect(this.element,
+          d[1]-this.delta[1], d[0]-this.delta[0]);
+    } else {
+      this.delta = d;
+    }
+
+    if(this.options.zindex)
+      this.element.style.zIndex = this.originalZ;
+
+    if(this.options.endeffect) 
+      this.options.endeffect(this.element);
+      
+    Draggables.deactivate(this);
+    Droppables.reset();
+  },
+  
+  keyPress: function(event) {
+    if(event.keyCode!=Event.KEY_ESC) return;
+    this.finishDrag(event, false);
+    Event.stop(event);
+  },
+  
+  endDrag: function(event) {
+    if(!this.dragging) return;
+    this.stopScrolling();
+    this.finishDrag(event, true);
+    Event.stop(event);
+  },
+  
+  draw: function(point) {
+    var pos = Position.cumulativeOffset(this.element);
+    if(this.options.ghosting) {
+      var r   = Position.realOffset(this.element);
+      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+    }
+    
+    var d = this.currentDelta();
+    pos[0] -= d[0]; pos[1] -= d[1];
+    
+    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+    }
+    
+    var p = [0,1].map(function(i){ 
+      return (point[i]-pos[i]-this.offset[i]) 
+    }.bind(this));
+    
+    if(this.options.snap) {
+      if(Object.isFunction(this.options.snap)) {
+        p = this.options.snap(p[0],p[1],this);
+      } else {
+      if(Object.isArray(this.options.snap)) {
+        p = p.map( function(v, i) {
+          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
+      } else {
+        p = p.map( function(v) {
+          return (v/this.options.snap).round()*this.options.snap }.bind(this))
+      }
+    }}
+    
+    var style = this.element.style;
+    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+      style.left = p[0] + "px";
+    if((!this.options.constraint) || (this.options.constraint=='vertical'))
+      style.top  = p[1] + "px";
+    
+    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
+  },
+  
+  stopScrolling: function() {
+    if(this.scrollInterval) {
+      clearInterval(this.scrollInterval);
+      this.scrollInterval = null;
+      Draggables._lastScrollPointer = null;
+    }
+  },
+  
+  startScrolling: function(speed) {
+    if(!(speed[0] || speed[1])) return;
+    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
+    this.lastScrolled = new Date();
+    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
+  },
+  
+  scroll: function() {
+    var current = new Date();
+    var delta = current - this.lastScrolled;
+    this.lastScrolled = current;
+    if(this.options.scroll == window) {
+      with (this._getWindowScroll(this.options.scroll)) {
+        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+          var d = delta / 1000;
+          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
+        }
+      }
+    } else {
+      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
+    }
+    
+    Position.prepare();
+    Droppables.show(Draggables._lastPointer, this.element);
+    Draggables.notify('onDrag', this);
+    if (this._isScrollChild) {
+      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
+      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
+      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
+      if (Draggables._lastScrollPointer[0] < 0)
+        Draggables._lastScrollPointer[0] = 0;
+      if (Draggables._lastScrollPointer[1] < 0)
+        Draggables._lastScrollPointer[1] = 0;
+      this.draw(Draggables._lastScrollPointer);
+    }
+    
+    if(this.options.change) this.options.change(this);
+  },
+  
+  _getWindowScroll: function(w) {
+    var T, L, W, H;
+    with (w.document) {
+      if (w.document.documentElement && documentElement.scrollTop) {
+        T = documentElement.scrollTop;
+        L = documentElement.scrollLeft;
+      } else if (w.document.body) {
+        T = body.scrollTop;
+        L = body.scrollLeft;
+      }
+      if (w.innerWidth) {
+        W = w.innerWidth;
+        H = w.innerHeight;
+      } else if (w.document.documentElement && documentElement.clientWidth) {
+        W = documentElement.clientWidth;
+        H = documentElement.clientHeight;
+      } else {
+        W = body.offsetWidth;
+        H = body.offsetHeight
+      }
+    }
+    return { top: T, left: L, width: W, height: H };
+  }
+});
+
+Draggable._dragging = { };
+
+/*--------------------------------------------------------------------------*/
+
+var SortableObserver = Class.create({
+  initialize: function(element, observer) {
+    this.element   = $(element);
+    this.observer  = observer;
+    this.lastValue = Sortable.serialize(this.element);
+  },
+  
+  onStart: function() {
+    this.lastValue = Sortable.serialize(this.element);
+  },
+  
+  onEnd: function() {
+    Sortable.unmark();
+    if(this.lastValue != Sortable.serialize(this.element))
+      this.observer(this.element)
+  }
+});
+
+var Sortable = {
+  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
+  
+  sortables: { },
+  
+  _findRootElement: function(element) {
+    while (element.tagName.toUpperCase() != "BODY") {  
+      if(element.id && Sortable.sortables[element.id]) return element;
+      element = element.parentNode;
+    }
+  },
+
+  options: function(element) {
+    element = Sortable._findRootElement($(element));
+    if(!element) return;
+    return Sortable.sortables[element.id];
+  },
+  
+  destroy: function(element){
+    var s = Sortable.options(element);
+    
+    if(s) {
+      Draggables.removeObserver(s.element);
+      s.droppables.each(function(d){ Droppables.remove(d) });
+      s.draggables.invoke('destroy');
+      
+      delete Sortable.sortables[s.element.id];
+    }
+  },
+
+  create: function(element) {
+    element = $(element);
+    var options = Object.extend({ 
+      element:     element,
+      tag:         'li',       // assumes li children, override with tag: 'tagname'
+      dropOnEmpty: false,
+      tree:        false,
+      treeTag:     'ul',
+      overlap:     'vertical', // one of 'vertical', 'horizontal'
+      constraint:  'vertical', // one of 'vertical', 'horizontal', false
+      containment: element,    // also takes array of elements (or id's); or false
+      handle:      false,      // or a CSS class
+      only:        false,
+      delay:       0,
+      hoverclass:  null,
+      ghosting:    false,
+      quiet:       false, 
+      scroll:      false,
+      scrollSensitivity: 20,
+      scrollSpeed: 15,
+      format:      this.SERIALIZE_RULE,
+      
+      // these take arrays of elements or ids and can be 
+      // used for better initialization performance
+      elements:    false,
+      handles:     false,
+      
+      onChange:    Prototype.emptyFunction,
+      onUpdate:    Prototype.emptyFunction
+    }, arguments[1] || { });
+
+    // clear any old sortable with same element
+    this.destroy(element);
+
+    // build options for the draggables
+    var options_for_draggable = {
+      revert:      true,
+      quiet:       options.quiet,
+      scroll:      options.scroll,
+      scrollSpeed: options.scrollSpeed,
+      scrollSensitivity: options.scrollSensitivity,
+      delay:       options.delay,
+      ghosting:    options.ghosting,
+      constraint:  options.constraint,
+      handle:      options.handle };
+
+    if(options.starteffect)
+      options_for_draggable.starteffect = options.starteffect;
+
+    if(options.reverteffect)
+      options_for_draggable.reverteffect = options.reverteffect;
+    else
+      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
+        element.style.top  = 0;
+        element.style.left = 0;
+      };
+
+    if(options.endeffect)
+      options_for_draggable.endeffect = options.endeffect;
+
+    if(options.zindex)
+      options_for_draggable.zindex = options.zindex;
+
+    // build options for the droppables  
+    var options_for_droppable = {
+      overlap:     options.overlap,
+      containment: options.containment,
+      tree:        options.tree,
+      hoverclass:  options.hoverclass,
+      onHover:     Sortable.onHover
+    }
+    
+    var options_for_tree = {
+      onHover:      Sortable.onEmptyHover,
+      overlap:      options.overlap,
+      containment:  options.containment,
+      hoverclass:   options.hoverclass
+    }
+
+    // fix for gecko engine
+    Element.cleanWhitespace(element); 
+
+    options.draggables = [];
+    options.droppables = [];
+
+    // drop on empty handling
+    if(options.dropOnEmpty || options.tree) {
+      Droppables.add(element, options_for_tree);
+      options.droppables.push(element);
+    }
+
+    (options.elements || this.findElements(element, options) || []).each( function(e,i) {
+      var handle = options.handles ? $(options.handles[i]) :
+        (options.handle ? $(e).select('.' + options.handle)[0] : e); 
+      options.draggables.push(
+        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
+      Droppables.add(e, options_for_droppable);
+      if(options.tree) e.treeNode = element;
+      options.droppables.push(e);      
+    });
+    
+    if(options.tree) {
+      (Sortable.findTreeElements(element, options) || []).each( function(e) {
+        Droppables.add(e, options_for_tree);
+        e.treeNode = element;
+        options.droppables.push(e);
+      });
+    }
+
+    // keep reference
+    this.sortables[element.id] = options;
+
+    // for onupdate
+    Draggables.addObserver(new SortableObserver(element, options.onUpdate));
+
+  },
+
+  // return all suitable-for-sortable elements in a guaranteed order
+  findElements: function(element, options) {
+    return Element.findChildren(
+      element, options.only, options.tree ? true : false, options.tag);
+  },
+  
+  findTreeElements: function(element, options) {
+    return Element.findChildren(
+      element, options.only, options.tree ? true : false, options.treeTag);
+  },
+
+  onHover: function(element, dropon, overlap) {
+    if(Element.isParent(dropon, element)) return;
+
+    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
+      return;
+    } else if(overlap>0.5) {
+      Sortable.mark(dropon, 'before');
+      if(dropon.previousSibling != element) {
+        var oldParentNode = element.parentNode;
+        element.style.visibility = "hidden"; // fix gecko rendering
+        dropon.parentNode.insertBefore(element, dropon);
+        if(dropon.parentNode!=oldParentNode) 
+          Sortable.options(oldParentNode).onChange(element);
+        Sortable.options(dropon.parentNode).onChange(element);
+      }
+    } else {
+      Sortable.mark(dropon, 'after');
+      var nextElement = dropon.nextSibling || null;
+      if(nextElement != element) {
+        var oldParentNode = element.parentNode;
+        element.style.visibility = "hidden"; // fix gecko rendering
+        dropon.parentNode.insertBefore(element, nextElement);
+        if(dropon.parentNode!=oldParentNode) 
+          Sortable.options(oldParentNode).onChange(element);
+        Sortable.options(dropon.parentNode).onChange(element);
+      }
+    }
+  },
+  
+  onEmptyHover: function(element, dropon, overlap) {
+    var oldParentNode = element.parentNode;
+    var droponOptions = Sortable.options(dropon);
+        
+    if(!Element.isParent(dropon, element)) {
+      var index;
+      
+      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
+      var child = null;
+            
+      if(children) {
+        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+        
+        for (index = 0; index < children.length; index += 1) {
+          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
+            offset -= Element.offsetSize (children[index], droponOptions.overlap);
+          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+            child = index + 1 < children.length ? children[index + 1] : null;
+            break;
+          } else {
+            child = children[index];
+            break;
+          }
+        }
+      }
+      
+      dropon.insertBefore(element, child);
+      
+      Sortable.options(oldParentNode).onChange(element);
+      droponOptions.onChange(element);
+    }
+  },
+
+  unmark: function() {
+    if(Sortable._marker) Sortable._marker.hide();
+  },
+
+  mark: function(dropon, position) {
+    // mark on ghosting only
+    var sortable = Sortable.options(dropon.parentNode);
+    if(sortable && !sortable.ghosting) return; 
+
+    if(!Sortable._marker) {
+      Sortable._marker = 
+        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
+          hide().addClassName('dropmarker').setStyle({position:'absolute'});
+      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
+    }    
+    var offsets = Position.cumulativeOffset(dropon);
+    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
+    
+    if(position=='after')
+      if(sortable.overlap == 'horizontal') 
+        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
+      else
+        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
+    
+    Sortable._marker.show();
+  },
+  
+  _tree: function(element, options, parent) {
+    var children = Sortable.findElements(element, options) || [];
+  
+    for (var i = 0; i < children.length; ++i) {
+      var match = children[i].id.match(options.format);
+
+      if (!match) continue;
+      
+      var child = {
+        id: encodeURIComponent(match ? match[1] : null),
+        element: element,
+        parent: parent,
+        children: [],
+        position: parent.children.length,
+        container: $(children[i]).down(options.treeTag)
+      }
+      
+      /* Get the element containing the children and recurse over it */
+      if (child.container)
+        this._tree(child.container, options, child)
+      
+      parent.children.push (child);
+    }
+
+    return parent; 
+  },
+
+  tree: function(element) {
+    element = $(element);
+    var sortableOptions = this.options(element);
+    var options = Object.extend({
+      tag: sortableOptions.tag,
+      treeTag: sortableOptions.treeTag,
+      only: sortableOptions.only,
+      name: element.id,
+      format: sortableOptions.format
+    }, arguments[1] || { });
+    
+    var root = {
+      id: null,
+      parent: null,
+      children: [],
+      container: element,
+      position: 0
+    }
+    
+    return Sortable._tree(element, options, root);
+  },
+
+  /* Construct a [i] index for a particular node */
+  _constructIndex: function(node) {
+    var index = '';
+    do {
+      if (node.id) index = '[' + node.position + ']' + index;
+    } while ((node = node.parent) != null);
+    return index;
+  },
+
+  sequence: function(element) {
+    element = $(element);
+    var options = Object.extend(this.options(element), arguments[1] || { });
+    
+    return $(this.findElements(element, options) || []).map( function(item) {
+      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+    });
+  },
+
+  setSequence: function(element, new_sequence) {
+    element = $(element);
+    var options = Object.extend(this.options(element), arguments[2] || { });
+    
+    var nodeMap = { };
+    this.findElements(element, options).each( function(n) {
+        if (n.id.match(options.format))
+            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
+        n.parentNode.removeChild(n);
+    });
+   
+    new_sequence.each(function(ident) {
+      var n = nodeMap[ident];
+      if (n) {
+        n[1].appendChild(n[0]);
+        delete nodeMap[ident];
+      }
+    });
+  },
+  
+  serialize: function(element) {
+    element = $(element);
+    var options = Object.extend(Sortable.options(element), arguments[1] || { });
+    var name = encodeURIComponent(
+      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
+    
+    if (options.tree) {
+      return Sortable.tree(element, arguments[1]).children.map( function (item) {
+        return [name + Sortable._constructIndex(item) + "[id]=" + 
+                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+      }).flatten().join('&');
+    } else {
+      return Sortable.sequence(element, arguments[1]).map( function(item) {
+        return name + "[]=" + encodeURIComponent(item);
+      }).join('&');
+    }
+  }
+}
+
+// Returns true if child is contained within element
+Element.isParent = function(child, element) {
+  if (!child.parentNode || child == element) return false;
+  if (child.parentNode == element) return true;
+  return Element.isParent(child.parentNode, element);
+}
+
+Element.findChildren = function(element, only, recursive, tagName) {   
+  if(!element.hasChildNodes()) return null;
+  tagName = tagName.toUpperCase();
+  if(only) only = [only].flatten();
+  var elements = [];
+  $A(element.childNodes).each( function(e) {
+    if(e.tagName && e.tagName.toUpperCase()==tagName &&
+      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
+        elements.push(e);
+    if(recursive) {
+      var grandchildren = Element.findChildren(e, only, recursive, tagName);
+      if(grandchildren) elements.push(grandchildren);
+    }
+  });
+
+  return (elements.length>0 ? elements.flatten() : []);
+}
+
+Element.offsetSize = function (element, type) {
+  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
+}
Index: /branches/features/grailsUpgrade/web-app/js/prototype/effects.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/effects.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/effects.js	(revision 875)
@@ -0,0 +1,1122 @@
+// script.aculo.us effects.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Contributors:
+//  Justin Palmer (http://encytemedia.com/)
+//  Mark Pilgrim (http://diveintomark.org/)
+//  Martin Bialasinki
+// 
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/ 
+
+// converts rgb() and #xxx to #xxxxxx format,  
+// returns self (or first argument) if not convertable  
+String.prototype.parseColor = function() {  
+  var color = '#';
+  if (this.slice(0,4) == 'rgb(') {  
+    var cols = this.slice(4,this.length-1).split(',');  
+    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
+  } else {  
+    if (this.slice(0,1) == '#') {  
+      if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
+      if (this.length==7) color = this.toLowerCase();  
+    }  
+  }  
+  return (color.length==7 ? color : (arguments[0] || this));  
+};
+
+/*--------------------------------------------------------------------------*/
+
+Element.collectTextNodes = function(element) {  
+  return $A($(element).childNodes).collect( function(node) {
+    return (node.nodeType==3 ? node.nodeValue : 
+      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
+  }).flatten().join('');
+};
+
+Element.collectTextNodesIgnoreClass = function(element, className) {  
+  return $A($(element).childNodes).collect( function(node) {
+    return (node.nodeType==3 ? node.nodeValue : 
+      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
+        Element.collectTextNodesIgnoreClass(node, className) : ''));
+  }).flatten().join('');
+};
+
+Element.setContentZoom = function(element, percent) {
+  element = $(element);  
+  element.setStyle({fontSize: (percent/100) + 'em'});   
+  if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+  return element;
+};
+
+Element.getInlineOpacity = function(element){
+  return $(element).style.opacity || '';
+};
+
+Element.forceRerendering = function(element) {
+  try {
+    element = $(element);
+    var n = document.createTextNode(' ');
+    element.appendChild(n);
+    element.removeChild(n);
+  } catch(e) { }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Effect = {
+  _elementDoesNotExistError: {
+    name: 'ElementDoesNotExistError',
+    message: 'The specified DOM element does not exist, but is required for this effect to operate'
+  },
+  Transitions: {
+    linear: Prototype.K,
+    sinoidal: function(pos) {
+      return (-Math.cos(pos*Math.PI)/2) + 0.5;
+    },
+    reverse: function(pos) {
+      return 1-pos;
+    },
+    flicker: function(pos) {
+      var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
+      return pos > 1 ? 1 : pos;
+    },
+    wobble: function(pos) {
+      return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
+    },
+    pulse: function(pos, pulses) { 
+      pulses = pulses || 5; 
+      return (
+        ((pos % (1/pulses)) * pulses).round() == 0 ? 
+              ((pos * pulses * 2) - (pos * pulses * 2).floor()) : 
+          1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
+        );
+    },
+    spring: function(pos) { 
+      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); 
+    },
+    none: function(pos) {
+      return 0;
+    },
+    full: function(pos) {
+      return 1;
+    }
+  },
+  DefaultOptions: {
+    duration:   1.0,   // seconds
+    fps:        100,   // 100= assume 66fps max.
+    sync:       false, // true for combining
+    from:       0.0,
+    to:         1.0,
+    delay:      0.0,
+    queue:      'parallel'
+  },
+  tagifyText: function(element) {
+    var tagifyStyle = 'position:relative';
+    if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
+    
+    element = $(element);
+    $A(element.childNodes).each( function(child) {
+      if (child.nodeType==3) {
+        child.nodeValue.toArray().each( function(character) {
+          element.insertBefore(
+            new Element('span', {style: tagifyStyle}).update(
+              character == ' ' ? String.fromCharCode(160) : character), 
+              child);
+        });
+        Element.remove(child);
+      }
+    });
+  },
+  multiple: function(element, effect) {
+    var elements;
+    if (((typeof element == 'object') || 
+        Object.isFunction(element)) && 
+       (element.length))
+      elements = element;
+    else
+      elements = $(element).childNodes;
+      
+    var options = Object.extend({
+      speed: 0.1,
+      delay: 0.0
+    }, arguments[2] || { });
+    var masterDelay = options.delay;
+
+    $A(elements).each( function(element, index) {
+      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
+    });
+  },
+  PAIRS: {
+    'slide':  ['SlideDown','SlideUp'],
+    'blind':  ['BlindDown','BlindUp'],
+    'appear': ['Appear','Fade']
+  },
+  toggle: function(element, effect) {
+    element = $(element);
+    effect = (effect || 'appear').toLowerCase();
+    var options = Object.extend({
+      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
+    }, arguments[2] || { });
+    Effect[element.visible() ? 
+      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+  }
+};
+
+Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
+
+/* ------------- core effects ------------- */
+
+Effect.ScopedQueue = Class.create(Enumerable, {
+  initialize: function() {
+    this.effects  = [];
+    this.interval = null;    
+  },
+  _each: function(iterator) {
+    this.effects._each(iterator);
+  },
+  add: function(effect) {
+    var timestamp = new Date().getTime();
+    
+    var position = Object.isString(effect.options.queue) ? 
+      effect.options.queue : effect.options.queue.position;
+    
+    switch(position) {
+      case 'front':
+        // move unstarted effects after this effect  
+        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
+            e.startOn  += effect.finishOn;
+            e.finishOn += effect.finishOn;
+          });
+        break;
+      case 'with-last':
+        timestamp = this.effects.pluck('startOn').max() || timestamp;
+        break;
+      case 'end':
+        // start effect after last queued effect has finished
+        timestamp = this.effects.pluck('finishOn').max() || timestamp;
+        break;
+    }
+    
+    effect.startOn  += timestamp;
+    effect.finishOn += timestamp;
+
+    if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
+      this.effects.push(effect);
+    
+    if (!this.interval)
+      this.interval = setInterval(this.loop.bind(this), 15);
+  },
+  remove: function(effect) {
+    this.effects = this.effects.reject(function(e) { return e==effect });
+    if (this.effects.length == 0) {
+      clearInterval(this.interval);
+      this.interval = null;
+    }
+  },
+  loop: function() {
+    var timePos = new Date().getTime();
+    for(var i=0, len=this.effects.length;i<len;i++) 
+      this.effects[i] && this.effects[i].loop(timePos);
+  }
+});
+
+Effect.Queues = {
+  instances: $H(),
+  get: function(queueName) {
+    if (!Object.isString(queueName)) return queueName;
+    
+    return this.instances.get(queueName) ||
+      this.instances.set(queueName, new Effect.ScopedQueue());
+  }
+};
+Effect.Queue = Effect.Queues.get('global');
+
+Effect.Base = Class.create({
+  position: null,
+  start: function(options) {
+    function codeForEvent(options,eventName){
+      return (
+        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
+        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
+      );
+    }
+    if (options && options.transition === false) options.transition = Effect.Transitions.linear;
+    this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
+    this.currentFrame = 0;
+    this.state        = 'idle';
+    this.startOn      = this.options.delay*1000;
+    this.finishOn     = this.startOn+(this.options.duration*1000);
+    this.fromToDelta  = this.options.to-this.options.from;
+    this.totalTime    = this.finishOn-this.startOn;
+    this.totalFrames  = this.options.fps*this.options.duration;
+    
+    eval('this.render = function(pos){ '+
+      'if (this.state=="idle"){this.state="running";'+
+      codeForEvent(this.options,'beforeSetup')+
+      (this.setup ? 'this.setup();':'')+ 
+      codeForEvent(this.options,'afterSetup')+
+      '};if (this.state=="running"){'+
+      'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
+      'this.position=pos;'+
+      codeForEvent(this.options,'beforeUpdate')+
+      (this.update ? 'this.update(pos);':'')+
+      codeForEvent(this.options,'afterUpdate')+
+      '}}');
+    
+    this.event('beforeStart');
+    if (!this.options.sync)
+      Effect.Queues.get(Object.isString(this.options.queue) ? 
+        'global' : this.options.queue.scope).add(this);
+  },
+  loop: function(timePos) {
+    if (timePos >= this.startOn) {
+      if (timePos >= this.finishOn) {
+        this.render(1.0);
+        this.cancel();
+        this.event('beforeFinish');
+        if (this.finish) this.finish(); 
+        this.event('afterFinish');
+        return;  
+      }
+      var pos   = (timePos - this.startOn) / this.totalTime,
+          frame = (pos * this.totalFrames).round();
+      if (frame > this.currentFrame) {
+        this.render(pos);
+        this.currentFrame = frame;
+      }
+    }
+  },
+  cancel: function() {
+    if (!this.options.sync)
+      Effect.Queues.get(Object.isString(this.options.queue) ? 
+        'global' : this.options.queue.scope).remove(this);
+    this.state = 'finished';
+  },
+  event: function(eventName) {
+    if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
+    if (this.options[eventName]) this.options[eventName](this);
+  },
+  inspect: function() {
+    var data = $H();
+    for(property in this)
+      if (!Object.isFunction(this[property])) data.set(property, this[property]);
+    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
+  }
+});
+
+Effect.Parallel = Class.create(Effect.Base, {
+  initialize: function(effects) {
+    this.effects = effects || [];
+    this.start(arguments[1]);
+  },
+  update: function(position) {
+    this.effects.invoke('render', position);
+  },
+  finish: function(position) {
+    this.effects.each( function(effect) {
+      effect.render(1.0);
+      effect.cancel();
+      effect.event('beforeFinish');
+      if (effect.finish) effect.finish(position);
+      effect.event('afterFinish');
+    });
+  }
+});
+
+Effect.Tween = Class.create(Effect.Base, {
+  initialize: function(object, from, to) {
+    object = Object.isString(object) ? $(object) : object;
+    var args = $A(arguments), method = args.last(), 
+      options = args.length == 5 ? args[3] : null;
+    this.method = Object.isFunction(method) ? method.bind(object) :
+      Object.isFunction(object[method]) ? object[method].bind(object) : 
+      function(value) { object[method] = value };
+    this.start(Object.extend({ from: from, to: to }, options || { }));
+  },
+  update: function(position) {
+    this.method(position);
+  }
+});
+
+Effect.Event = Class.create(Effect.Base, {
+  initialize: function() {
+    this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
+  },
+  update: Prototype.emptyFunction
+});
+
+Effect.Opacity = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    // make this work on IE on elements without 'layout'
+    if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+      this.element.setStyle({zoom: 1});
+    var options = Object.extend({
+      from: this.element.getOpacity() || 0.0,
+      to:   1.0
+    }, arguments[1] || { });
+    this.start(options);
+  },
+  update: function(position) {
+    this.element.setOpacity(position);
+  }
+});
+
+Effect.Move = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      x:    0,
+      y:    0,
+      mode: 'relative'
+    }, arguments[1] || { });
+    this.start(options);
+  },
+  setup: function() {
+    this.element.makePositioned();
+    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
+    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
+    if (this.options.mode == 'absolute') {
+      this.options.x = this.options.x - this.originalLeft;
+      this.options.y = this.options.y - this.originalTop;
+    }
+  },
+  update: function(position) {
+    this.element.setStyle({
+      left: (this.options.x  * position + this.originalLeft).round() + 'px',
+      top:  (this.options.y  * position + this.originalTop).round()  + 'px'
+    });
+  }
+});
+
+// for backwards compatibility
+Effect.MoveBy = function(element, toTop, toLeft) {
+  return new Effect.Move(element, 
+    Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
+};
+
+Effect.Scale = Class.create(Effect.Base, {
+  initialize: function(element, percent) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      scaleX: true,
+      scaleY: true,
+      scaleContent: true,
+      scaleFromCenter: false,
+      scaleMode: 'box',        // 'box' or 'contents' or { } with provided values
+      scaleFrom: 100.0,
+      scaleTo:   percent
+    }, arguments[2] || { });
+    this.start(options);
+  },
+  setup: function() {
+    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+    this.elementPositioning = this.element.getStyle('position');
+    
+    this.originalStyle = { };
+    ['top','left','width','height','fontSize'].each( function(k) {
+      this.originalStyle[k] = this.element.style[k];
+    }.bind(this));
+      
+    this.originalTop  = this.element.offsetTop;
+    this.originalLeft = this.element.offsetLeft;
+    
+    var fontSize = this.element.getStyle('font-size') || '100%';
+    ['em','px','%','pt'].each( function(fontSizeType) {
+      if (fontSize.indexOf(fontSizeType)>0) {
+        this.fontSize     = parseFloat(fontSize);
+        this.fontSizeType = fontSizeType;
+      }
+    }.bind(this));
+    
+    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+    
+    this.dims = null;
+    if (this.options.scaleMode=='box')
+      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+    if (/^content/.test(this.options.scaleMode))
+      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+    if (!this.dims)
+      this.dims = [this.options.scaleMode.originalHeight,
+                   this.options.scaleMode.originalWidth];
+  },
+  update: function(position) {
+    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
+    if (this.options.scaleContent && this.fontSize)
+      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
+    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
+  },
+  finish: function(position) {
+    if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
+  },
+  setDimensions: function(height, width) {
+    var d = { };
+    if (this.options.scaleX) d.width = width.round() + 'px';
+    if (this.options.scaleY) d.height = height.round() + 'px';
+    if (this.options.scaleFromCenter) {
+      var topd  = (height - this.dims[0])/2;
+      var leftd = (width  - this.dims[1])/2;
+      if (this.elementPositioning == 'absolute') {
+        if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
+        if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
+      } else {
+        if (this.options.scaleY) d.top = -topd + 'px';
+        if (this.options.scaleX) d.left = -leftd + 'px';
+      }
+    }
+    this.element.setStyle(d);
+  }
+});
+
+Effect.Highlight = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
+    this.start(options);
+  },
+  setup: function() {
+    // Prevent executing on elements not in the layout flow
+    if (this.element.getStyle('display')=='none') { this.cancel(); return; }
+    // Disable background image during the effect
+    this.oldStyle = { };
+    if (!this.options.keepBackgroundImage) {
+      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
+      this.element.setStyle({backgroundImage: 'none'});
+    }
+    if (!this.options.endcolor)
+      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
+    if (!this.options.restorecolor)
+      this.options.restorecolor = this.element.getStyle('background-color');
+    // init color calculations
+    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
+    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
+  },
+  update: function(position) {
+    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
+      return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
+  },
+  finish: function() {
+    this.element.setStyle(Object.extend(this.oldStyle, {
+      backgroundColor: this.options.restorecolor
+    }));
+  }
+});
+
+Effect.ScrollTo = function(element) {
+  var options = arguments[1] || { },
+    scrollOffsets = document.viewport.getScrollOffsets(),
+    elementOffsets = $(element).cumulativeOffset(),
+    max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();  
+
+  if (options.offset) elementOffsets[1] += options.offset;
+
+  return new Effect.Tween(null,
+    scrollOffsets.top,
+    elementOffsets[1] > max ? max : elementOffsets[1],
+    options,
+    function(p){ scrollTo(scrollOffsets.left, p.round()) }
+  );
+};
+
+/* ------------- combination effects ------------- */
+
+Effect.Fade = function(element) {
+  element = $(element);
+  var oldOpacity = element.getInlineOpacity();
+  var options = Object.extend({
+    from: element.getOpacity() || 1.0,
+    to:   0.0,
+    afterFinishInternal: function(effect) { 
+      if (effect.options.to!=0) return;
+      effect.element.hide().setStyle({opacity: oldOpacity}); 
+    }
+  }, arguments[1] || { });
+  return new Effect.Opacity(element,options);
+};
+
+Effect.Appear = function(element) {
+  element = $(element);
+  var options = Object.extend({
+  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
+  to:   1.0,
+  // force Safari to render floated elements properly
+  afterFinishInternal: function(effect) {
+    effect.element.forceRerendering();
+  },
+  beforeSetup: function(effect) {
+    effect.element.setOpacity(effect.options.from).show(); 
+  }}, arguments[1] || { });
+  return new Effect.Opacity(element,options);
+};
+
+Effect.Puff = function(element) {
+  element = $(element);
+  var oldStyle = { 
+    opacity: element.getInlineOpacity(), 
+    position: element.getStyle('position'),
+    top:  element.style.top,
+    left: element.style.left,
+    width: element.style.width,
+    height: element.style.height
+  };
+  return new Effect.Parallel(
+   [ new Effect.Scale(element, 200, 
+      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
+     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
+     Object.extend({ duration: 1.0, 
+      beforeSetupInternal: function(effect) {
+        Position.absolutize(effect.effects[0].element)
+      },
+      afterFinishInternal: function(effect) {
+         effect.effects[0].element.hide().setStyle(oldStyle); }
+     }, arguments[1] || { })
+   );
+};
+
+Effect.BlindUp = function(element) {
+  element = $(element);
+  element.makeClipping();
+  return new Effect.Scale(element, 0,
+    Object.extend({ scaleContent: false, 
+      scaleX: false, 
+      restoreAfterFinish: true,
+      afterFinishInternal: function(effect) {
+        effect.element.hide().undoClipping();
+      } 
+    }, arguments[1] || { })
+  );
+};
+
+Effect.BlindDown = function(element) {
+  element = $(element);
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, 100, Object.extend({ 
+    scaleContent: false, 
+    scaleX: false,
+    scaleFrom: 0,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
+    },  
+    afterFinishInternal: function(effect) {
+      effect.element.undoClipping();
+    }
+  }, arguments[1] || { }));
+};
+
+Effect.SwitchOff = function(element) {
+  element = $(element);
+  var oldOpacity = element.getInlineOpacity();
+  return new Effect.Appear(element, Object.extend({
+    duration: 0.4,
+    from: 0,
+    transition: Effect.Transitions.flicker,
+    afterFinishInternal: function(effect) {
+      new Effect.Scale(effect.element, 1, { 
+        duration: 0.3, scaleFromCenter: true,
+        scaleX: false, scaleContent: false, restoreAfterFinish: true,
+        beforeSetup: function(effect) { 
+          effect.element.makePositioned().makeClipping();
+        },
+        afterFinishInternal: function(effect) {
+          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
+        }
+      })
+    }
+  }, arguments[1] || { }));
+};
+
+Effect.DropOut = function(element) {
+  element = $(element);
+  var oldStyle = {
+    top: element.getStyle('top'),
+    left: element.getStyle('left'),
+    opacity: element.getInlineOpacity() };
+  return new Effect.Parallel(
+    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
+      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
+    Object.extend(
+      { duration: 0.5,
+        beforeSetup: function(effect) {
+          effect.effects[0].element.makePositioned(); 
+        },
+        afterFinishInternal: function(effect) {
+          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
+        } 
+      }, arguments[1] || { }));
+};
+
+Effect.Shake = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    distance: 20,
+    duration: 0.5
+  }, arguments[1] || {});
+  var distance = parseFloat(options.distance);
+  var split = parseFloat(options.duration) / 10.0;
+  var oldStyle = {
+    top: element.getStyle('top'),
+    left: element.getStyle('left') };
+    return new Effect.Move(element,
+      { x:  distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
+    new Effect.Move(effect.element,
+      { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
+        effect.element.undoPositioned().setStyle(oldStyle);
+  }}) }}) }}) }}) }}) }});
+};
+
+Effect.SlideDown = function(element) {
+  element = $(element).cleanWhitespace();
+  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
+  var oldInnerBottom = element.down().getStyle('bottom');
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, 100, Object.extend({ 
+    scaleContent: false, 
+    scaleX: false, 
+    scaleFrom: window.opera ? 0 : 1,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makePositioned();
+      effect.element.down().makePositioned();
+      if (window.opera) effect.element.setStyle({top: ''});
+      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
+    },
+    afterUpdateInternal: function(effect) {
+      effect.element.down().setStyle({bottom:
+        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.undoClipping().undoPositioned();
+      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
+    }, arguments[1] || { })
+  );
+};
+
+Effect.SlideUp = function(element) {
+  element = $(element).cleanWhitespace();
+  var oldInnerBottom = element.down().getStyle('bottom');
+  var elementDimensions = element.getDimensions();
+  return new Effect.Scale(element, window.opera ? 0 : 1,
+   Object.extend({ scaleContent: false, 
+    scaleX: false, 
+    scaleMode: 'box',
+    scaleFrom: 100,
+    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
+    restoreAfterFinish: true,
+    afterSetup: function(effect) {
+      effect.element.makePositioned();
+      effect.element.down().makePositioned();
+      if (window.opera) effect.element.setStyle({top: ''});
+      effect.element.makeClipping().show();
+    },  
+    afterUpdateInternal: function(effect) {
+      effect.element.down().setStyle({bottom:
+        (effect.dims[0] - effect.element.clientHeight) + 'px' });
+    },
+    afterFinishInternal: function(effect) {
+      effect.element.hide().undoClipping().undoPositioned();
+      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
+    }
+   }, arguments[1] || { })
+  );
+};
+
+// Bug in opera makes the TD containing this element expand for a instance after finish 
+Effect.Squish = function(element) {
+  return new Effect.Scale(element, window.opera ? 1 : 0, { 
+    restoreAfterFinish: true,
+    beforeSetup: function(effect) {
+      effect.element.makeClipping(); 
+    },  
+    afterFinishInternal: function(effect) {
+      effect.element.hide().undoClipping(); 
+    }
+  });
+};
+
+Effect.Grow = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    direction: 'center',
+    moveTransition: Effect.Transitions.sinoidal,
+    scaleTransition: Effect.Transitions.sinoidal,
+    opacityTransition: Effect.Transitions.full
+  }, arguments[1] || { });
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    height: element.style.height,
+    width: element.style.width,
+    opacity: element.getInlineOpacity() };
+
+  var dims = element.getDimensions();    
+  var initialMoveX, initialMoveY;
+  var moveX, moveY;
+  
+  switch (options.direction) {
+    case 'top-left':
+      initialMoveX = initialMoveY = moveX = moveY = 0; 
+      break;
+    case 'top-right':
+      initialMoveX = dims.width;
+      initialMoveY = moveY = 0;
+      moveX = -dims.width;
+      break;
+    case 'bottom-left':
+      initialMoveX = moveX = 0;
+      initialMoveY = dims.height;
+      moveY = -dims.height;
+      break;
+    case 'bottom-right':
+      initialMoveX = dims.width;
+      initialMoveY = dims.height;
+      moveX = -dims.width;
+      moveY = -dims.height;
+      break;
+    case 'center':
+      initialMoveX = dims.width / 2;
+      initialMoveY = dims.height / 2;
+      moveX = -dims.width / 2;
+      moveY = -dims.height / 2;
+      break;
+  }
+  
+  return new Effect.Move(element, {
+    x: initialMoveX,
+    y: initialMoveY,
+    duration: 0.01, 
+    beforeSetup: function(effect) {
+      effect.element.hide().makeClipping().makePositioned();
+    },
+    afterFinishInternal: function(effect) {
+      new Effect.Parallel(
+        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
+          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
+          new Effect.Scale(effect.element, 100, {
+            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
+            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
+        ], Object.extend({
+             beforeSetup: function(effect) {
+               effect.effects[0].element.setStyle({height: '0px'}).show(); 
+             },
+             afterFinishInternal: function(effect) {
+               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
+             }
+           }, options)
+      )
+    }
+  });
+};
+
+Effect.Shrink = function(element) {
+  element = $(element);
+  var options = Object.extend({
+    direction: 'center',
+    moveTransition: Effect.Transitions.sinoidal,
+    scaleTransition: Effect.Transitions.sinoidal,
+    opacityTransition: Effect.Transitions.none
+  }, arguments[1] || { });
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    height: element.style.height,
+    width: element.style.width,
+    opacity: element.getInlineOpacity() };
+
+  var dims = element.getDimensions();
+  var moveX, moveY;
+  
+  switch (options.direction) {
+    case 'top-left':
+      moveX = moveY = 0;
+      break;
+    case 'top-right':
+      moveX = dims.width;
+      moveY = 0;
+      break;
+    case 'bottom-left':
+      moveX = 0;
+      moveY = dims.height;
+      break;
+    case 'bottom-right':
+      moveX = dims.width;
+      moveY = dims.height;
+      break;
+    case 'center':  
+      moveX = dims.width / 2;
+      moveY = dims.height / 2;
+      break;
+  }
+  
+  return new Effect.Parallel(
+    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
+      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
+      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
+    ], Object.extend({            
+         beforeStartInternal: function(effect) {
+           effect.effects[0].element.makePositioned().makeClipping(); 
+         },
+         afterFinishInternal: function(effect) {
+           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
+       }, options)
+  );
+};
+
+Effect.Pulsate = function(element) {
+  element = $(element);
+  var options    = arguments[1] || { };
+  var oldOpacity = element.getInlineOpacity();
+  var transition = options.transition || Effect.Transitions.sinoidal;
+  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
+  reverser.bind(transition);
+  return new Effect.Opacity(element, 
+    Object.extend(Object.extend({  duration: 2.0, from: 0,
+      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
+    }, options), {transition: reverser}));
+};
+
+Effect.Fold = function(element) {
+  element = $(element);
+  var oldStyle = {
+    top: element.style.top,
+    left: element.style.left,
+    width: element.style.width,
+    height: element.style.height };
+  element.makeClipping();
+  return new Effect.Scale(element, 5, Object.extend({   
+    scaleContent: false,
+    scaleX: false,
+    afterFinishInternal: function(effect) {
+    new Effect.Scale(element, 1, { 
+      scaleContent: false, 
+      scaleY: false,
+      afterFinishInternal: function(effect) {
+        effect.element.hide().undoClipping().setStyle(oldStyle);
+      } });
+  }}, arguments[1] || { }));
+};
+
+Effect.Morph = Class.create(Effect.Base, {
+  initialize: function(element) {
+    this.element = $(element);
+    if (!this.element) throw(Effect._elementDoesNotExistError);
+    var options = Object.extend({
+      style: { }
+    }, arguments[1] || { });
+    
+    if (!Object.isString(options.style)) this.style = $H(options.style);
+    else {
+      if (options.style.include(':'))
+        this.style = options.style.parseStyle();
+      else {
+        this.element.addClassName(options.style);
+        this.style = $H(this.element.getStyles());
+        this.element.removeClassName(options.style);
+        var css = this.element.getStyles();
+        this.style = this.style.reject(function(style) {
+          return style.value == css[style.key];
+        });
+        options.afterFinishInternal = function(effect) {
+          effect.element.addClassName(effect.options.style);
+          effect.transforms.each(function(transform) {
+            effect.element.style[transform.style] = '';
+          });
+        }
+      }
+    }
+    this.start(options);
+  },
+  
+  setup: function(){
+    function parseColor(color){
+      if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
+      color = color.parseColor();
+      return $R(0,2).map(function(i){
+        return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
+      });
+    }
+    this.transforms = this.style.map(function(pair){
+      var property = pair[0], value = pair[1], unit = null;
+
+      if (value.parseColor('#zzzzzz') != '#zzzzzz') {
+        value = value.parseColor();
+        unit  = 'color';
+      } else if (property == 'opacity') {
+        value = parseFloat(value);
+        if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
+          this.element.setStyle({zoom: 1});
+      } else if (Element.CSS_LENGTH.test(value)) {
+          var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+          value = parseFloat(components[1]);
+          unit = (components.length == 3) ? components[2] : null;
+      }
+
+      var originalValue = this.element.getStyle(property);
+      return { 
+        style: property.camelize(), 
+        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
+        targetValue: unit=='color' ? parseColor(value) : value,
+        unit: unit
+      };
+    }.bind(this)).reject(function(transform){
+      return (
+        (transform.originalValue == transform.targetValue) ||
+        (
+          transform.unit != 'color' &&
+          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
+        )
+      )
+    });
+  },
+  update: function(position) {
+    var style = { }, transform, i = this.transforms.length;
+    while(i--)
+      style[(transform = this.transforms[i]).style] = 
+        transform.unit=='color' ? '#'+
+          (Math.round(transform.originalValue[0]+
+            (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
+          (Math.round(transform.originalValue[1]+
+            (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
+          (Math.round(transform.originalValue[2]+
+            (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
+        (transform.originalValue +
+          (transform.targetValue - transform.originalValue) * position).toFixed(3) + 
+            (transform.unit === null ? '' : transform.unit);
+    this.element.setStyle(style, true);
+  }
+});
+
+Effect.Transform = Class.create({
+  initialize: function(tracks){
+    this.tracks  = [];
+    this.options = arguments[1] || { };
+    this.addTracks(tracks);
+  },
+  addTracks: function(tracks){
+    tracks.each(function(track){
+      track = $H(track);
+      var data = track.values().first();
+      this.tracks.push($H({
+        ids:     track.keys().first(),
+        effect:  Effect.Morph,
+        options: { style: data }
+      }));
+    }.bind(this));
+    return this;
+  },
+  play: function(){
+    return new Effect.Parallel(
+      this.tracks.map(function(track){
+        var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
+        var elements = [$(ids) || $$(ids)].flatten();
+        return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
+      }).flatten(),
+      this.options
+    );
+  }
+});
+
+Element.CSS_PROPERTIES = $w(
+  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
+  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
+  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
+  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
+  'fontSize fontWeight height left letterSpacing lineHeight ' +
+  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
+  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
+  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
+  'right textIndent top width wordSpacing zIndex');
+  
+Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+String.__parseStyleElement = document.createElement('div');
+String.prototype.parseStyle = function(){
+  var style, styleRules = $H();
+  if (Prototype.Browser.WebKit)
+    style = new Element('div',{style:this}).style;
+  else {
+    String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
+    style = String.__parseStyleElement.childNodes[0].style;
+  }
+  
+  Element.CSS_PROPERTIES.each(function(property){
+    if (style[property]) styleRules.set(property, style[property]); 
+  });
+  
+  if (Prototype.Browser.IE && this.include('opacity'))
+    styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
+
+  return styleRules;
+};
+
+if (document.defaultView && document.defaultView.getComputedStyle) {
+  Element.getStyles = function(element) {
+    var css = document.defaultView.getComputedStyle($(element), null);
+    return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
+      styles[property] = css[property];
+      return styles;
+    });
+  };
+} else {
+  Element.getStyles = function(element) {
+    element = $(element);
+    var css = element.currentStyle, styles;
+    styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
+      hash.set(property, css[property]);
+      return hash;
+    });
+    if (!styles.opacity) styles.set('opacity', element.getOpacity());
+    return styles;
+  };
+};
+
+Effect.Methods = {
+  morph: function(element, style) {
+    element = $(element);
+    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
+    return element;
+  },
+  visualEffect: function(element, effect, options) {
+    element = $(element)
+    var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
+    new Effect[klass](element, options);
+    return element;
+  },
+  highlight: function(element, options) {
+    element = $(element);
+    new Effect.Highlight(element, options);
+    return element;
+  }
+};
+
+$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
+  'pulsate shake puff squish switchOff dropOut').each(
+  function(effect) { 
+    Effect.Methods[effect] = function(element, options){
+      element = $(element);
+      Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
+      return element;
+    }
+  }
+);
+
+$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( 
+  function(f) { Effect.Methods[f] = Element[f]; }
+);
+
+Element.addMethods(Effect.Methods);
Index: /branches/features/grailsUpgrade/web-app/js/prototype/prototype.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/prototype.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/prototype.js	(revision 875)
@@ -0,0 +1,4184 @@
+/*  Prototype JavaScript framework, version 1.6.0
+ *  (c) 2005-2007 Sam Stephenson
+ *
+ *  Prototype is freely distributable under the terms of an MIT-style license.
+ *  For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+var Prototype = {
+  Version: '1.6.0',
+
+  Browser: {
+    IE:     !!(window.attachEvent && !window.opera),
+    Opera:  !!window.opera,
+    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
+    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
+  },
+
+  BrowserFeatures: {
+    XPath: !!document.evaluate,
+    ElementExtensions: !!window.HTMLElement,
+    SpecificElementExtensions:
+      document.createElement('div').__proto__ &&
+      document.createElement('div').__proto__ !==
+        document.createElement('form').__proto__
+  },
+
+  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
+  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+  emptyFunction: function() { },
+  K: function(x) { return x }
+};
+
+if (Prototype.Browser.MobileSafari)
+  Prototype.BrowserFeatures.SpecificElementExtensions = false;
+
+if (Prototype.Browser.WebKit)
+  Prototype.BrowserFeatures.XPath = false;
+
+/* Based on Alex Arnell's inheritance implementation. */
+var Class = {
+  create: function() {
+    var parent = null, properties = $A(arguments);
+    if (Object.isFunction(properties[0]))
+      parent = properties.shift();
+
+    function klass() {
+      this.initialize.apply(this, arguments);
+    }
+
+    Object.extend(klass, Class.Methods);
+    klass.superclass = parent;
+    klass.subclasses = [];
+
+    if (parent) {
+      var subclass = function() { };
+      subclass.prototype = parent.prototype;
+      klass.prototype = new subclass;
+      parent.subclasses.push(klass);
+    }
+
+    for (var i = 0; i < properties.length; i++)
+      klass.addMethods(properties[i]);
+
+    if (!klass.prototype.initialize)
+      klass.prototype.initialize = Prototype.emptyFunction;
+
+    klass.prototype.constructor = klass;
+
+    return klass;
+  }
+};
+
+Class.Methods = {
+  addMethods: function(source) {
+    var ancestor   = this.superclass && this.superclass.prototype;
+    var properties = Object.keys(source);
+
+    if (!Object.keys({ toString: true }).length)
+      properties.push("toString", "valueOf");
+
+    for (var i = 0, length = properties.length; i < length; i++) {
+      var property = properties[i], value = source[property];
+      if (ancestor && Object.isFunction(value) &&
+          value.argumentNames().first() == "$super") {
+        var method = value, value = Object.extend((function(m) {
+          return function() { return ancestor[m].apply(this, arguments) };
+        })(property).wrap(method), {
+          valueOf:  function() { return method },
+          toString: function() { return method.toString() }
+        });
+      }
+      this.prototype[property] = value;
+    }
+
+    return this;
+  }
+};
+
+var Abstract = { };
+
+Object.extend = function(destination, source) {
+  for (var property in source)
+    destination[property] = source[property];
+  return destination;
+};
+
+Object.extend(Object, {
+  inspect: function(object) {
+    try {
+      if (object === undefined) return 'undefined';
+      if (object === null) return 'null';
+      return object.inspect ? object.inspect() : object.toString();
+    } catch (e) {
+      if (e instanceof RangeError) return '...';
+      throw e;
+    }
+  },
+
+  toJSON: function(object) {
+    var type = typeof object;
+    switch (type) {
+      case 'undefined':
+      case 'function':
+      case 'unknown': return;
+      case 'boolean': return object.toString();
+    }
+
+    if (object === null) return 'null';
+    if (object.toJSON) return object.toJSON();
+    if (Object.isElement(object)) return;
+
+    var results = [];
+    for (var property in object) {
+      var value = Object.toJSON(object[property]);
+      if (value !== undefined)
+        results.push(property.toJSON() + ': ' + value);
+    }
+
+    return '{' + results.join(', ') + '}';
+  },
+
+  toQueryString: function(object) {
+    return $H(object).toQueryString();
+  },
+
+  toHTML: function(object) {
+    return object && object.toHTML ? object.toHTML() : String.interpret(object);
+  },
+
+  keys: function(object) {
+    var keys = [];
+    for (var property in object)
+      keys.push(property);
+    return keys;
+  },
+
+  values: function(object) {
+    var values = [];
+    for (var property in object)
+      values.push(object[property]);
+    return values;
+  },
+
+  clone: function(object) {
+    return Object.extend({ }, object);
+  },
+
+  isElement: function(object) {
+    return object && object.nodeType == 1;
+  },
+
+  isArray: function(object) {
+    return object && object.constructor === Array;
+  },
+
+  isHash: function(object) {
+    return object instanceof Hash;
+  },
+
+  isFunction: function(object) {
+    return typeof object == "function";
+  },
+
+  isString: function(object) {
+    return typeof object == "string";
+  },
+
+  isNumber: function(object) {
+    return typeof object == "number";
+  },
+
+  isUndefined: function(object) {
+    return typeof object == "undefined";
+  }
+});
+
+Object.extend(Function.prototype, {
+  argumentNames: function() {
+    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
+    return names.length == 1 && !names[0] ? [] : names;
+  },
+
+  bind: function() {
+    if (arguments.length < 2 && arguments[0] === undefined) return this;
+    var __method = this, args = $A(arguments), object = args.shift();
+    return function() {
+      return __method.apply(object, args.concat($A(arguments)));
+    }
+  },
+
+  bindAsEventListener: function() {
+    var __method = this, args = $A(arguments), object = args.shift();
+    return function(event) {
+      return __method.apply(object, [event || window.event].concat(args));
+    }
+  },
+
+  curry: function() {
+    if (!arguments.length) return this;
+    var __method = this, args = $A(arguments);
+    return function() {
+      return __method.apply(this, args.concat($A(arguments)));
+    }
+  },
+
+  delay: function() {
+    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
+    return window.setTimeout(function() {
+      return __method.apply(__method, args);
+    }, timeout);
+  },
+
+  wrap: function(wrapper) {
+    var __method = this;
+    return function() {
+      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
+    }
+  },
+
+  methodize: function() {
+    if (this._methodized) return this._methodized;
+    var __method = this;
+    return this._methodized = function() {
+      return __method.apply(null, [this].concat($A(arguments)));
+    };
+  }
+});
+
+Function.prototype.defer = Function.prototype.delay.curry(0.01);
+
+Date.prototype.toJSON = function() {
+  return '"' + this.getUTCFullYear() + '-' +
+    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+    this.getUTCDate().toPaddedString(2) + 'T' +
+    this.getUTCHours().toPaddedString(2) + ':' +
+    this.getUTCMinutes().toPaddedString(2) + ':' +
+    this.getUTCSeconds().toPaddedString(2) + 'Z"';
+};
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) { }
+    }
+
+    return returnValue;
+  }
+};
+
+RegExp.prototype.match = RegExp.prototype.test;
+
+RegExp.escape = function(str) {
+  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+};
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create({
+  initialize: function(callback, frequency) {
+    this.callback = callback;
+    this.frequency = frequency;
+    this.currentlyExecuting = false;
+
+    this.registerCallback();
+  },
+
+  registerCallback: function() {
+    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+  },
+
+  execute: function() {
+    this.callback(this);
+  },
+
+  stop: function() {
+    if (!this.timer) return;
+    clearInterval(this.timer);
+    this.timer = null;
+  },
+
+  onTimerEvent: function() {
+    if (!this.currentlyExecuting) {
+      try {
+        this.currentlyExecuting = true;
+        this.execute();
+      } finally {
+        this.currentlyExecuting = false;
+      }
+    }
+  }
+});
+Object.extend(String, {
+  interpret: function(value) {
+    return value == null ? '' : String(value);
+  },
+  specialChar: {
+    '\b': '\\b',
+    '\t': '\\t',
+    '\n': '\\n',
+    '\f': '\\f',
+    '\r': '\\r',
+    '\\': '\\\\'
+  }
+});
+
+Object.extend(String.prototype, {
+  gsub: function(pattern, replacement) {
+    var result = '', source = this, match;
+    replacement = arguments.callee.prepareReplacement(replacement);
+
+    while (source.length > 0) {
+      if (match = source.match(pattern)) {
+        result += source.slice(0, match.index);
+        result += String.interpret(replacement(match));
+        source  = source.slice(match.index + match[0].length);
+      } else {
+        result += source, source = '';
+      }
+    }
+    return result;
+  },
+
+  sub: function(pattern, replacement, count) {
+    replacement = this.gsub.prepareReplacement(replacement);
+    count = count === undefined ? 1 : count;
+
+    return this.gsub(pattern, function(match) {
+      if (--count < 0) return match[0];
+      return replacement(match);
+    });
+  },
+
+  scan: function(pattern, iterator) {
+    this.gsub(pattern, iterator);
+    return String(this);
+  },
+
+  truncate: function(length, truncation) {
+    length = length || 30;
+    truncation = truncation === undefined ? '...' : truncation;
+    return this.length > length ?
+      this.slice(0, length - truncation.length) + truncation : String(this);
+  },
+
+  strip: function() {
+    return this.replace(/^\s+/, '').replace(/\s+$/, '');
+  },
+
+  stripTags: function() {
+    return this.replace(/<\/?[^>]+>/gi, '');
+  },
+
+  stripScripts: function() {
+    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+  },
+
+  extractScripts: function() {
+    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+    return (this.match(matchAll) || []).map(function(scriptTag) {
+      return (scriptTag.match(matchOne) || ['', ''])[1];
+    });
+  },
+
+  evalScripts: function() {
+    return this.extractScripts().map(function(script) { return eval(script) });
+  },
+
+  escapeHTML: function() {
+    var self = arguments.callee;
+    self.text.data = this;
+    return self.div.innerHTML;
+  },
+
+  unescapeHTML: function() {
+    var div = new Element('div');
+    div.innerHTML = this.stripTags();
+    return div.childNodes[0] ? (div.childNodes.length > 1 ?
+      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+      div.childNodes[0].nodeValue) : '';
+  },
+
+  toQueryParams: function(separator) {
+    var match = this.strip().match(/([^?#]*)(#.*)?$/);
+    if (!match) return { };
+
+    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+      if ((pair = pair.split('='))[0]) {
+        var key = decodeURIComponent(pair.shift());
+        var value = pair.length > 1 ? pair.join('=') : pair[0];
+        if (value != undefined) value = decodeURIComponent(value);
+
+        if (key in hash) {
+          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+          hash[key].push(value);
+        }
+        else hash[key] = value;
+      }
+      return hash;
+    });
+  },
+
+  toArray: function() {
+    return this.split('');
+  },
+
+  succ: function() {
+    return this.slice(0, this.length - 1) +
+      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+  },
+
+  times: function(count) {
+    return count < 1 ? '' : new Array(count + 1).join(this);
+  },
+
+  camelize: function() {
+    var parts = this.split('-'), len = parts.length;
+    if (len == 1) return parts[0];
+
+    var camelized = this.charAt(0) == '-'
+      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+      : parts[0];
+
+    for (var i = 1; i < len; i++)
+      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+    return camelized;
+  },
+
+  capitalize: function() {
+    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+  },
+
+  underscore: function() {
+    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+  },
+
+  dasherize: function() {
+    return this.gsub(/_/,'-');
+  },
+
+  inspect: function(useDoubleQuotes) {
+    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+      var character = String.specialChar[match[0]];
+      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+    });
+    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+  },
+
+  toJSON: function() {
+    return this.inspect(true);
+  },
+
+  unfilterJSON: function(filter) {
+    return this.sub(filter || Prototype.JSONFilter, '#{1}');
+  },
+
+  isJSON: function() {
+    var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+  },
+
+  evalJSON: function(sanitize) {
+    var json = this.unfilterJSON();
+    try {
+      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+    } catch (e) { }
+    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+  },
+
+  include: function(pattern) {
+    return this.indexOf(pattern) > -1;
+  },
+
+  startsWith: function(pattern) {
+    return this.indexOf(pattern) === 0;
+  },
+
+  endsWith: function(pattern) {
+    var d = this.length - pattern.length;
+    return d >= 0 && this.lastIndexOf(pattern) === d;
+  },
+
+  empty: function() {
+    return this == '';
+  },
+
+  blank: function() {
+    return /^\s*$/.test(this);
+  },
+
+  interpolate: function(object, pattern) {
+    return new Template(this, pattern).evaluate(object);
+  }
+});
+
+if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+  escapeHTML: function() {
+    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+  },
+  unescapeHTML: function() {
+    return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+  }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+  if (Object.isFunction(replacement)) return replacement;
+  var template = new Template(replacement);
+  return function(match) { return template.evaluate(match) };
+};
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+Object.extend(String.prototype.escapeHTML, {
+  div:  document.createElement('div'),
+  text: document.createTextNode('')
+});
+
+with (String.prototype.escapeHTML) div.appendChild(text);
+
+var Template = Class.create({
+  initialize: function(template, pattern) {
+    this.template = template.toString();
+    this.pattern = pattern || Template.Pattern;
+  },
+
+  evaluate: function(object) {
+    if (Object.isFunction(object.toTemplateReplacements))
+      object = object.toTemplateReplacements();
+
+    return this.template.gsub(this.pattern, function(match) {
+      if (object == null) return '';
+
+      var before = match[1] || '';
+      if (before == '\\') return match[2];
+
+      var ctx = object, expr = match[3];
+      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/, match = pattern.exec(expr);
+      if (match == null) return before;
+
+      while (match != null) {
+        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
+        ctx = ctx[comp];
+        if (null == ctx || '' == match[3]) break;
+        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+        match = pattern.exec(expr);
+      }
+
+      return before + String.interpret(ctx);
+    }.bind(this));
+  }
+});
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+var $break = { };
+
+var Enumerable = {
+  each: function(iterator, context) {
+    var index = 0;
+    iterator = iterator.bind(context);
+    try {
+      this._each(function(value) {
+        iterator(value, index++);
+      });
+    } catch (e) {
+      if (e != $break) throw e;
+    }
+    return this;
+  },
+
+  eachSlice: function(number, iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var index = -number, slices = [], array = this.toArray();
+    while ((index += number) < array.length)
+      slices.push(array.slice(index, index+number));
+    return slices.collect(iterator, context);
+  },
+
+  all: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result = true;
+    this.each(function(value, index) {
+      result = result && !!iterator(value, index);
+      if (!result) throw $break;
+    });
+    return result;
+  },
+
+  any: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result = false;
+    this.each(function(value, index) {
+      if (result = !!iterator(value, index))
+        throw $break;
+    });
+    return result;
+  },
+
+  collect: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var results = [];
+    this.each(function(value, index) {
+      results.push(iterator(value, index));
+    });
+    return results;
+  },
+
+  detect: function(iterator, context) {
+    iterator = iterator.bind(context);
+    var result;
+    this.each(function(value, index) {
+      if (iterator(value, index)) {
+        result = value;
+        throw $break;
+      }
+    });
+    return result;
+  },
+
+  findAll: function(iterator, context) {
+    iterator = iterator.bind(context);
+    var results = [];
+    this.each(function(value, index) {
+      if (iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  grep: function(filter, iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var results = [];
+
+    if (Object.isString(filter))
+      filter = new RegExp(filter);
+
+    this.each(function(value, index) {
+      if (filter.match(value))
+        results.push(iterator(value, index));
+    });
+    return results;
+  },
+
+  include: function(object) {
+    if (Object.isFunction(this.indexOf))
+      if (this.indexOf(object) != -1) return true;
+
+    var found = false;
+    this.each(function(value) {
+      if (value == object) {
+        found = true;
+        throw $break;
+      }
+    });
+    return found;
+  },
+
+  inGroupsOf: function(number, fillWith) {
+    fillWith = fillWith === undefined ? null : fillWith;
+    return this.eachSlice(number, function(slice) {
+      while(slice.length < number) slice.push(fillWith);
+      return slice;
+    });
+  },
+
+  inject: function(memo, iterator, context) {
+    iterator = iterator.bind(context);
+    this.each(function(value, index) {
+      memo = iterator(memo, value, index);
+    });
+    return memo;
+  },
+
+  invoke: function(method) {
+    var args = $A(arguments).slice(1);
+    return this.map(function(value) {
+      return value[method].apply(value, args);
+    });
+  },
+
+  max: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator(value, index);
+      if (result == undefined || value >= result)
+        result = value;
+    });
+    return result;
+  },
+
+  min: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var result;
+    this.each(function(value, index) {
+      value = iterator(value, index);
+      if (result == undefined || value < result)
+        result = value;
+    });
+    return result;
+  },
+
+  partition: function(iterator, context) {
+    iterator = iterator ? iterator.bind(context) : Prototype.K;
+    var trues = [], falses = [];
+    this.each(function(value, index) {
+      (iterator(value, index) ?
+        trues : falses).push(value);
+    });
+    return [trues, falses];
+  },
+
+  pluck: function(property) {
+    var results = [];
+    this.each(function(value) {
+      results.push(value[property]);
+    });
+    return results;
+  },
+
+  reject: function(iterator, context) {
+    iterator = iterator.bind(context);
+    var results = [];
+    this.each(function(value, index) {
+      if (!iterator(value, index))
+        results.push(value);
+    });
+    return results;
+  },
+
+  sortBy: function(iterator, context) {
+    iterator = iterator.bind(context);
+    return this.map(function(value, index) {
+      return {value: value, criteria: iterator(value, index)};
+    }).sort(function(left, right) {
+      var a = left.criteria, b = right.criteria;
+      return a < b ? -1 : a > b ? 1 : 0;
+    }).pluck('value');
+  },
+
+  toArray: function() {
+    return this.map();
+  },
+
+  zip: function() {
+    var iterator = Prototype.K, args = $A(arguments);
+    if (Object.isFunction(args.last()))
+      iterator = args.pop();
+
+    var collections = [this].concat(args).map($A);
+    return this.map(function(value, index) {
+      return iterator(collections.pluck(index));
+    });
+  },
+
+  size: function() {
+    return this.toArray().length;
+  },
+
+  inspect: function() {
+    return '#<Enumerable:' + this.toArray().inspect() + '>';
+  }
+};
+
+Object.extend(Enumerable, {
+  map:     Enumerable.collect,
+  find:    Enumerable.detect,
+  select:  Enumerable.findAll,
+  filter:  Enumerable.findAll,
+  member:  Enumerable.include,
+  entries: Enumerable.toArray,
+  every:   Enumerable.all,
+  some:    Enumerable.any
+});
+function $A(iterable) {
+  if (!iterable) return [];
+  if (iterable.toArray) return iterable.toArray();
+  var length = iterable.length, results = new Array(length);
+  while (length--) results[length] = iterable[length];
+  return results;
+}
+
+if (Prototype.Browser.WebKit) {
+  function $A(iterable) {
+    if (!iterable) return [];
+    if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
+        iterable.toArray) return iterable.toArray();
+    var length = iterable.length, results = new Array(length);
+    while (length--) results[length] = iterable[length];
+    return results;
+  }
+}
+
+Array.from = $A;
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+  _each: function(iterator) {
+    for (var i = 0, length = this.length; i < length; i++)
+      iterator(this[i]);
+  },
+
+  clear: function() {
+    this.length = 0;
+    return this;
+  },
+
+  first: function() {
+    return this[0];
+  },
+
+  last: function() {
+    return this[this.length - 1];
+  },
+
+  compact: function() {
+    return this.select(function(value) {
+      return value != null;
+    });
+  },
+
+  flatten: function() {
+    return this.inject([], function(array, value) {
+      return array.concat(Object.isArray(value) ?
+        value.flatten() : [value]);
+    });
+  },
+
+  without: function() {
+    var values = $A(arguments);
+    return this.select(function(value) {
+      return !values.include(value);
+    });
+  },
+
+  reverse: function(inline) {
+    return (inline !== false ? this : this.toArray())._reverse();
+  },
+
+  reduce: function() {
+    return this.length > 1 ? this : this[0];
+  },
+
+  uniq: function(sorted) {
+    return this.inject([], function(array, value, index) {
+      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+        array.push(value);
+      return array;
+    });
+  },
+
+  intersect: function(array) {
+    return this.uniq().findAll(function(item) {
+      return array.detect(function(value) { return item === value });
+    });
+  },
+
+  clone: function() {
+    return [].concat(this);
+  },
+
+  size: function() {
+    return this.length;
+  },
+
+  inspect: function() {
+    return '[' + this.map(Object.inspect).join(', ') + ']';
+  },
+
+  toJSON: function() {
+    var results = [];
+    this.each(function(object) {
+      var value = Object.toJSON(object);
+      if (value !== undefined) results.push(value);
+    });
+    return '[' + results.join(', ') + ']';
+  }
+});
+
+// use native browser JS 1.6 implementation if available
+if (Object.isFunction(Array.prototype.forEach))
+  Array.prototype._each = Array.prototype.forEach;
+
+if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
+  i || (i = 0);
+  var length = this.length;
+  if (i < 0) i = length + i;
+  for (; i < length; i++)
+    if (this[i] === item) return i;
+  return -1;
+};
+
+if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
+  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+  var n = this.slice(0, i).reverse().indexOf(item);
+  return (n < 0) ? n : i - n - 1;
+};
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string) {
+  if (!Object.isString(string)) return [];
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
+
+if (Prototype.Browser.Opera){
+  Array.prototype.concat = function() {
+    var array = [];
+    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+    for (var i = 0, length = arguments.length; i < length; i++) {
+      if (Object.isArray(arguments[i])) {
+        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+          array.push(arguments[i][j]);
+      } else {
+        array.push(arguments[i]);
+      }
+    }
+    return array;
+  };
+}
+Object.extend(Number.prototype, {
+  toColorPart: function() {
+    return this.toPaddedString(2, 16);
+  },
+
+  succ: function() {
+    return this + 1;
+  },
+
+  times: function(iterator) {
+    $R(0, this, true).each(iterator);
+    return this;
+  },
+
+  toPaddedString: function(length, radix) {
+    var string = this.toString(radix || 10);
+    return '0'.times(length - string.length) + string;
+  },
+
+  toJSON: function() {
+    return isFinite(this) ? this.toString() : 'null';
+  }
+});
+
+$w('abs round ceil floor').each(function(method){
+  Number.prototype[method] = Math[method].methodize();
+});
+function $H(object) {
+  return new Hash(object);
+};
+
+var Hash = Class.create(Enumerable, (function() {
+  if (function() {
+    var i = 0, Test = function(value) { this.key = value };
+    Test.prototype.key = 'foo';
+    for (var property in new Test('bar')) i++;
+    return i > 1;
+  }()) {
+    function each(iterator) {
+      var cache = [];
+      for (var key in this._object) {
+        var value = this._object[key];
+        if (cache.include(key)) continue;
+        cache.push(key);
+        var pair = [key, value];
+        pair.key = key;
+        pair.value = value;
+        iterator(pair);
+      }
+    }
+  } else {
+    function each(iterator) {
+      for (var key in this._object) {
+        var value = this._object[key], pair = [key, value];
+        pair.key = key;
+        pair.value = value;
+        iterator(pair);
+      }
+    }
+  }
+
+  function toQueryPair(key, value) {
+    if (Object.isUndefined(value)) return key;
+    return key + '=' + encodeURIComponent(String.interpret(value));
+  }
+
+  return {
+    initialize: function(object) {
+      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+    },
+
+    _each: each,
+
+    set: function(key, value) {
+      return this._object[key] = value;
+    },
+
+    get: function(key) {
+      return this._object[key];
+    },
+
+    unset: function(key) {
+      var value = this._object[key];
+      delete this._object[key];
+      return value;
+    },
+
+    toObject: function() {
+      return Object.clone(this._object);
+    },
+
+    keys: function() {
+      return this.pluck('key');
+    },
+
+    values: function() {
+      return this.pluck('value');
+    },
+
+    index: function(value) {
+      var match = this.detect(function(pair) {
+        return pair.value === value;
+      });
+      return match && match.key;
+    },
+
+    merge: function(object) {
+      return this.clone().update(object);
+    },
+
+    update: function(object) {
+      return new Hash(object).inject(this, function(result, pair) {
+        result.set(pair.key, pair.value);
+        return result;
+      });
+    },
+
+    toQueryString: function() {
+      return this.map(function(pair) {
+        var key = encodeURIComponent(pair.key), values = pair.value;
+
+        if (values && typeof values == 'object') {
+          if (Object.isArray(values))
+            return values.map(toQueryPair.curry(key)).join('&');
+        }
+        return toQueryPair(key, values);
+      }).join('&');
+    },
+
+    inspect: function() {
+      return '#<Hash:{' + this.map(function(pair) {
+        return pair.map(Object.inspect).join(': ');
+      }).join(', ') + '}>';
+    },
+
+    toJSON: function() {
+      return Object.toJSON(this.toObject());
+    },
+
+    clone: function() {
+      return new Hash(this);
+    }
+  }
+})());
+
+Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
+Hash.from = $H;
+var ObjectRange = Class.create(Enumerable, {
+  initialize: function(start, end, exclusive) {
+    this.start = start;
+    this.end = end;
+    this.exclusive = exclusive;
+  },
+
+  _each: function(iterator) {
+    var value = this.start;
+    while (this.include(value)) {
+      iterator(value);
+      value = value.succ();
+    }
+  },
+
+  include: function(value) {
+    if (value < this.start)
+      return false;
+    if (this.exclusive)
+      return value < this.end;
+    return value <= this.end;
+  }
+});
+
+var $R = function(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+};
+
+var Ajax = {
+  getTransport: function() {
+    return Try.these(
+      function() {return new XMLHttpRequest()},
+      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+    ) || false;
+  },
+
+  activeRequestCount: 0
+};
+
+Ajax.Responders = {
+  responders: [],
+
+  _each: function(iterator) {
+    this.responders._each(iterator);
+  },
+
+  register: function(responder) {
+    if (!this.include(responder))
+      this.responders.push(responder);
+  },
+
+  unregister: function(responder) {
+    this.responders = this.responders.without(responder);
+  },
+
+  dispatch: function(callback, request, transport, json) {
+    this.each(function(responder) {
+      if (Object.isFunction(responder[callback])) {
+        try {
+          responder[callback].apply(responder, [request, transport, json]);
+        } catch (e) { }
+      }
+    });
+  }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+  onCreate:   function() { Ajax.activeRequestCount++ },
+  onComplete: function() { Ajax.activeRequestCount-- }
+});
+
+Ajax.Base = Class.create({
+  initialize: function(options) {
+    this.options = {
+      method:       'post',
+      asynchronous: true,
+      contentType:  'application/x-www-form-urlencoded',
+      encoding:     'UTF-8',
+      parameters:   '',
+      evalJSON:     true,
+      evalJS:       true
+    };
+    Object.extend(this.options, options || { });
+
+    this.options.method = this.options.method.toLowerCase();
+    if (Object.isString(this.options.parameters))
+      this.options.parameters = this.options.parameters.toQueryParams();
+  }
+});
+
+Ajax.Request = Class.create(Ajax.Base, {
+  _complete: false,
+
+  initialize: function($super, url, options) {
+    $super(options);
+    this.transport = Ajax.getTransport();
+    this.request(url);
+  },
+
+  request: function(url) {
+    this.url = url;
+    this.method = this.options.method;
+    var params = Object.clone(this.options.parameters);
+
+    if (!['get', 'post'].include(this.method)) {
+      // simulate other verbs over post
+      params['_method'] = this.method;
+      this.method = 'post';
+    }
+
+    this.parameters = params;
+
+    if (params = Object.toQueryString(params)) {
+      // when GET, append parameters to URL
+      if (this.method == 'get')
+        this.url += (this.url.include('?') ? '&' : '?') + params;
+      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+        params += '&_=';
+    }
+
+    try {
+      var response = new Ajax.Response(this);
+      if (this.options.onCreate) this.options.onCreate(response);
+      Ajax.Responders.dispatch('onCreate', this, response);
+
+      this.transport.open(this.method.toUpperCase(), this.url,
+        this.options.asynchronous);
+
+      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
+
+      this.transport.onreadystatechange = this.onStateChange.bind(this);
+      this.setRequestHeaders();
+
+      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+      this.transport.send(this.body);
+
+      /* Force Firefox to handle ready state 4 for synchronous requests */
+      if (!this.options.asynchronous && this.transport.overrideMimeType)
+        this.onStateChange();
+
+    }
+    catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  onStateChange: function() {
+    var readyState = this.transport.readyState;
+    if (readyState > 1 && !((readyState == 4) && this._complete))
+      this.respondToReadyState(this.transport.readyState);
+  },
+
+  setRequestHeaders: function() {
+    var headers = {
+      'X-Requested-With': 'XMLHttpRequest',
+      'X-Prototype-Version': Prototype.Version,
+      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+    };
+
+    if (this.method == 'post') {
+      headers['Content-type'] = this.options.contentType +
+        (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+      /* Force "Connection: close" for older Mozilla browsers to work
+       * around a bug where XMLHttpRequest sends an incorrect
+       * Content-length header. See Mozilla Bugzilla #246651.
+       */
+      if (this.transport.overrideMimeType &&
+          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+            headers['Connection'] = 'close';
+    }
+
+    // user-defined headers
+    if (typeof this.options.requestHeaders == 'object') {
+      var extras = this.options.requestHeaders;
+
+      if (Object.isFunction(extras.push))
+        for (var i = 0, length = extras.length; i < length; i += 2)
+          headers[extras[i]] = extras[i+1];
+      else
+        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+    }
+
+    for (var name in headers)
+      this.transport.setRequestHeader(name, headers[name]);
+  },
+
+  success: function() {
+    var status = this.getStatus();
+    return !status || (status >= 200 && status < 300);
+  },
+
+  getStatus: function() {
+    try {
+      return this.transport.status || 0;
+    } catch (e) { return 0 }
+  },
+
+  respondToReadyState: function(readyState) {
+    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+    if (state == 'Complete') {
+      try {
+        this._complete = true;
+        (this.options['on' + response.status]
+         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+         || Prototype.emptyFunction)(response, response.headerJSON);
+      } catch (e) {
+        this.dispatchException(e);
+      }
+
+      var contentType = response.getHeader('Content-type');
+      if (this.options.evalJS == 'force'
+          || (this.options.evalJS && contentType
+          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+        this.evalResponse();
+    }
+
+    try {
+      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+    } catch (e) {
+      this.dispatchException(e);
+    }
+
+    if (state == 'Complete') {
+      // avoid memory leak in MSIE: clean up
+      this.transport.onreadystatechange = Prototype.emptyFunction;
+    }
+  },
+
+  getHeader: function(name) {
+    try {
+      return this.transport.getResponseHeader(name);
+    } catch (e) { return null }
+  },
+
+  evalResponse: function() {
+    try {
+      return eval((this.transport.responseText || '').unfilterJSON());
+    } catch (e) {
+      this.dispatchException(e);
+    }
+  },
+
+  dispatchException: function(exception) {
+    (this.options.onException || Prototype.emptyFunction)(this, exception);
+    Ajax.Responders.dispatch('onException', this, exception);
+  }
+});
+
+Ajax.Request.Events =
+  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Response = Class.create({
+  initialize: function(request){
+    this.request = request;
+    var transport  = this.transport  = request.transport,
+        readyState = this.readyState = transport.readyState;
+
+    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+      this.status       = this.getStatus();
+      this.statusText   = this.getStatusText();
+      this.responseText = String.interpret(transport.responseText);
+      this.headerJSON   = this._getHeaderJSON();
+    }
+
+    if(readyState == 4) {
+      var xml = transport.responseXML;
+      this.responseXML  = xml === undefined ? null : xml;
+      this.responseJSON = this._getResponseJSON();
+    }
+  },
+
+  status:      0,
+  statusText: '',
+
+  getStatus: Ajax.Request.prototype.getStatus,
+
+  getStatusText: function() {
+    try {
+      return this.transport.statusText || '';
+    } catch (e) { return '' }
+  },
+
+  getHeader: Ajax.Request.prototype.getHeader,
+
+  getAllHeaders: function() {
+    try {
+      return this.getAllResponseHeaders();
+    } catch (e) { return null }
+  },
+
+  getResponseHeader: function(name) {
+    return this.transport.getResponseHeader(name);
+  },
+
+  getAllResponseHeaders: function() {
+    return this.transport.getAllResponseHeaders();
+  },
+
+  _getHeaderJSON: function() {
+    var json = this.getHeader('X-JSON');
+    if (!json) return null;
+    json = decodeURIComponent(escape(json));
+    try {
+      return json.evalJSON(this.request.options.sanitizeJSON);
+    } catch (e) {
+      this.request.dispatchException(e);
+    }
+  },
+
+  _getResponseJSON: function() {
+    var options = this.request.options;
+    if (!options.evalJSON || (options.evalJSON != 'force' &&
+      !(this.getHeader('Content-type') || '').include('application/json')))
+        return null;
+    try {
+      return this.transport.responseText.evalJSON(options.sanitizeJSON);
+    } catch (e) {
+      this.request.dispatchException(e);
+    }
+  }
+});
+
+Ajax.Updater = Class.create(Ajax.Request, {
+  initialize: function($super, container, url, options) {
+    this.container = {
+      success: (container.success || container),
+      failure: (container.failure || (container.success ? null : container))
+    };
+
+    options = options || { };
+    var onComplete = options.onComplete;
+    options.onComplete = (function(response, param) {
+      this.updateContent(response.responseText);
+      if (Object.isFunction(onComplete)) onComplete(response, param);
+    }).bind(this);
+
+    $super(url, options);
+  },
+
+  updateContent: function(responseText) {
+    var receiver = this.container[this.success() ? 'success' : 'failure'],
+        options = this.options;
+
+    if (!options.evalScripts) responseText = responseText.stripScripts();
+
+    if (receiver = $(receiver)) {
+      if (options.insertion) {
+        if (Object.isString(options.insertion)) {
+          var insertion = { }; insertion[options.insertion] = responseText;
+          receiver.insert(insertion);
+        }
+        else options.insertion(receiver, responseText);
+      }
+      else receiver.update(responseText);
+    }
+
+    if (this.success()) {
+      if (this.onComplete) this.onComplete.bind(this).defer();
+    }
+  }
+});
+
+Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+  initialize: function($super, container, url, options) {
+    $super(options);
+    this.onComplete = this.options.onComplete;
+
+    this.frequency = (this.options.frequency || 2);
+    this.decay = (this.options.decay || 1);
+
+    this.updater = { };
+    this.container = container;
+    this.url = url;
+
+    this.start();
+  },
+
+  start: function() {
+    this.options.onComplete = this.updateComplete.bind(this);
+    this.onTimerEvent();
+  },
+
+  stop: function() {
+    this.updater.options.onComplete = undefined;
+    clearTimeout(this.timer);
+    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+  },
+
+  updateComplete: function(response) {
+    if (this.options.decay) {
+      this.decay = (response.responseText == this.lastText ?
+        this.decay * this.options.decay : 1);
+
+      this.lastText = response.responseText;
+    }
+    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+  },
+
+  onTimerEvent: function() {
+    this.updater = new Ajax.Updater(this.container, this.url, this.options);
+  }
+});
+function $(element) {
+  if (arguments.length > 1) {
+    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+      elements.push($(arguments[i]));
+    return elements;
+  }
+  if (Object.isString(element))
+    element = document.getElementById(element);
+  return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+  document._getElementsByXPath = function(expression, parentElement) {
+    var results = [];
+    var query = document.evaluate(expression, $(parentElement) || document,
+      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    for (var i = 0, length = query.snapshotLength; i < length; i++)
+      results.push(Element.extend(query.snapshotItem(i)));
+    return results;
+  };
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Node) var Node = { };
+
+if (!Node.ELEMENT_NODE) {
+  // DOM level 2 ECMAScript Language Binding
+  Object.extend(Node, {
+    ELEMENT_NODE: 1,
+    ATTRIBUTE_NODE: 2,
+    TEXT_NODE: 3,
+    CDATA_SECTION_NODE: 4,
+    ENTITY_REFERENCE_NODE: 5,
+    ENTITY_NODE: 6,
+    PROCESSING_INSTRUCTION_NODE: 7,
+    COMMENT_NODE: 8,
+    DOCUMENT_NODE: 9,
+    DOCUMENT_TYPE_NODE: 10,
+    DOCUMENT_FRAGMENT_NODE: 11,
+    NOTATION_NODE: 12
+  });
+}
+
+(function() {
+  var element = this.Element;
+  this.Element = function(tagName, attributes) {
+    attributes = attributes || { };
+    tagName = tagName.toLowerCase();
+    var cache = Element.cache;
+    if (Prototype.Browser.IE && attributes.name) {
+      tagName = '<' + tagName + ' name="' + attributes.name + '">';
+      delete attributes.name;
+      return Element.writeAttribute(document.createElement(tagName), attributes);
+    }
+    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+  };
+  Object.extend(this.Element, element || { });
+}).call(window);
+
+Element.cache = { };
+
+Element.Methods = {
+  visible: function(element) {
+    return $(element).style.display != 'none';
+  },
+
+  toggle: function(element) {
+    element = $(element);
+    Element[Element.visible(element) ? 'hide' : 'show'](element);
+    return element;
+  },
+
+  hide: function(element) {
+    $(element).style.display = 'none';
+    return element;
+  },
+
+  show: function(element) {
+    $(element).style.display = '';
+    return element;
+  },
+
+  remove: function(element) {
+    element = $(element);
+    element.parentNode.removeChild(element);
+    return element;
+  },
+
+  update: function(element, content) {
+    element = $(element);
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) return element.update().insert(content);
+    content = Object.toHTML(content);
+    element.innerHTML = content.stripScripts();
+    content.evalScripts.bind(content).defer();
+    return element;
+  },
+
+  replace: function(element, content) {
+    element = $(element);
+    if (content && content.toElement) content = content.toElement();
+    else if (!Object.isElement(content)) {
+      content = Object.toHTML(content);
+      var range = element.ownerDocument.createRange();
+      range.selectNode(element);
+      content.evalScripts.bind(content).defer();
+      content = range.createContextualFragment(content.stripScripts());
+    }
+    element.parentNode.replaceChild(content, element);
+    return element;
+  },
+
+  insert: function(element, insertions) {
+    element = $(element);
+
+    if (Object.isString(insertions) || Object.isNumber(insertions) ||
+        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+          insertions = {bottom:insertions};
+
+    var content, t, range;
+
+    for (position in insertions) {
+      content  = insertions[position];
+      position = position.toLowerCase();
+      t = Element._insertionTranslations[position];
+
+      if (content && content.toElement) content = content.toElement();
+      if (Object.isElement(content)) {
+        t.insert(element, content);
+        continue;
+      }
+
+      content = Object.toHTML(content);
+
+      range = element.ownerDocument.createRange();
+      t.initializeRange(element, range);
+      t.insert(element, range.createContextualFragment(content.stripScripts()));
+
+      content.evalScripts.bind(content).defer();
+    }
+
+    return element;
+  },
+
+  wrap: function(element, wrapper, attributes) {
+    element = $(element);
+    if (Object.isElement(wrapper))
+      $(wrapper).writeAttribute(attributes || { });
+    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+    else wrapper = new Element('div', wrapper);
+    if (element.parentNode)
+      element.parentNode.replaceChild(wrapper, element);
+    wrapper.appendChild(element);
+    return wrapper;
+  },
+
+  inspect: function(element) {
+    element = $(element);
+    var result = '<' + element.tagName.toLowerCase();
+    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+      var property = pair.first(), attribute = pair.last();
+      var value = (element[property] || '').toString();
+      if (value) result += ' ' + attribute + '=' + value.inspect(true);
+    });
+    return result + '>';
+  },
+
+  recursivelyCollect: function(element, property) {
+    element = $(element);
+    var elements = [];
+    while (element = element[property])
+      if (element.nodeType == 1)
+        elements.push(Element.extend(element));
+    return elements;
+  },
+
+  ancestors: function(element) {
+    return $(element).recursivelyCollect('parentNode');
+  },
+
+  descendants: function(element) {
+    return $A($(element).getElementsByTagName('*')).each(Element.extend);
+  },
+
+  firstDescendant: function(element) {
+    element = $(element).firstChild;
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    return $(element);
+  },
+
+  immediateDescendants: function(element) {
+    if (!(element = $(element).firstChild)) return [];
+    while (element && element.nodeType != 1) element = element.nextSibling;
+    if (element) return [element].concat($(element).nextSiblings());
+    return [];
+  },
+
+  previousSiblings: function(element) {
+    return $(element).recursivelyCollect('previousSibling');
+  },
+
+  nextSiblings: function(element) {
+    return $(element).recursivelyCollect('nextSibling');
+  },
+
+  siblings: function(element) {
+    element = $(element);
+    return element.previousSiblings().reverse().concat(element.nextSiblings());
+  },
+
+  match: function(element, selector) {
+    if (Object.isString(selector))
+      selector = new Selector(selector);
+    return selector.match($(element));
+  },
+
+  up: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(element.parentNode);
+    var ancestors = element.ancestors();
+    return expression ? Selector.findElement(ancestors, expression, index) :
+      ancestors[index || 0];
+  },
+
+  down: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return element.firstDescendant();
+    var descendants = element.descendants();
+    return expression ? Selector.findElement(descendants, expression, index) :
+      descendants[index || 0];
+  },
+
+  previous: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+    var previousSiblings = element.previousSiblings();
+    return expression ? Selector.findElement(previousSiblings, expression, index) :
+      previousSiblings[index || 0];
+  },
+
+  next: function(element, expression, index) {
+    element = $(element);
+    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+    var nextSiblings = element.nextSiblings();
+    return expression ? Selector.findElement(nextSiblings, expression, index) :
+      nextSiblings[index || 0];
+  },
+
+  select: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element, args);
+  },
+
+  adjacent: function() {
+    var args = $A(arguments), element = $(args.shift());
+    return Selector.findChildElements(element.parentNode, args).without(element);
+  },
+
+  identify: function(element) {
+    element = $(element);
+    var id = element.readAttribute('id'), self = arguments.callee;
+    if (id) return id;
+    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
+    element.writeAttribute('id', id);
+    return id;
+  },
+
+  readAttribute: function(element, name) {
+    element = $(element);
+    if (Prototype.Browser.IE) {
+      var t = Element._attributeTranslations.read;
+      if (t.values[name]) return t.values[name](element, name);
+      if (t.names[name]) name = t.names[name];
+      if (name.include(':')) {
+        return (!element.attributes || !element.attributes[name]) ? null :
+         element.attributes[name].value;
+      }
+    }
+    return element.getAttribute(name);
+  },
+
+  writeAttribute: function(element, name, value) {
+    element = $(element);
+    var attributes = { }, t = Element._attributeTranslations.write;
+
+    if (typeof name == 'object') attributes = name;
+    else attributes[name] = value === undefined ? true : value;
+
+    for (var attr in attributes) {
+      var name = t.names[attr] || attr, value = attributes[attr];
+      if (t.values[attr]) name = t.values[attr](element, value);
+      if (value === false || value === null)
+        element.removeAttribute(name);
+      else if (value === true)
+        element.setAttribute(name, name);
+      else element.setAttribute(name, value);
+    }
+    return element;
+  },
+
+  getHeight: function(element) {
+    return $(element).getDimensions().height;
+  },
+
+  getWidth: function(element) {
+    return $(element).getDimensions().width;
+  },
+
+  classNames: function(element) {
+    return new Element.ClassNames(element);
+  },
+
+  hasClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    var elementClassName = element.className;
+    return (elementClassName.length > 0 && (elementClassName == className ||
+      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+  },
+
+  addClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    if (!element.hasClassName(className))
+      element.className += (element.className ? ' ' : '') + className;
+    return element;
+  },
+
+  removeClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    element.className = element.className.replace(
+      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+    return element;
+  },
+
+  toggleClassName: function(element, className) {
+    if (!(element = $(element))) return;
+    return element[element.hasClassName(className) ?
+      'removeClassName' : 'addClassName'](className);
+  },
+
+  // removes whitespace-only text node children
+  cleanWhitespace: function(element) {
+    element = $(element);
+    var node = element.firstChild;
+    while (node) {
+      var nextNode = node.nextSibling;
+      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+        element.removeChild(node);
+      node = nextNode;
+    }
+    return element;
+  },
+
+  empty: function(element) {
+    return $(element).innerHTML.blank();
+  },
+
+  descendantOf: function(element, ancestor) {
+    element = $(element), ancestor = $(ancestor);
+
+    if (element.compareDocumentPosition)
+      return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+    if (element.sourceIndex && !Prototype.Browser.Opera) {
+      var e = element.sourceIndex, a = ancestor.sourceIndex,
+       nextAncestor = ancestor.nextSibling;
+      if (!nextAncestor) {
+        do { ancestor = ancestor.parentNode; }
+        while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
+      }
+      if (nextAncestor) return (e > a && e < nextAncestor.sourceIndex);
+    }
+
+    while (element = element.parentNode)
+      if (element == ancestor) return true;
+    return false;
+  },
+
+  scrollTo: function(element) {
+    element = $(element);
+    var pos = element.cumulativeOffset();
+    window.scrollTo(pos[0], pos[1]);
+    return element;
+  },
+
+  getStyle: function(element, style) {
+    element = $(element);
+    style = style == 'float' ? 'cssFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value) {
+      var css = document.defaultView.getComputedStyle(element, null);
+      value = css ? css[style] : null;
+    }
+    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+    return value == 'auto' ? null : value;
+  },
+
+  getOpacity: function(element) {
+    return $(element).getStyle('opacity');
+  },
+
+  setStyle: function(element, styles) {
+    element = $(element);
+    var elementStyle = element.style, match;
+    if (Object.isString(styles)) {
+      element.style.cssText += ';' + styles;
+      return styles.include('opacity') ?
+        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+    }
+    for (var property in styles)
+      if (property == 'opacity') element.setOpacity(styles[property]);
+      else
+        elementStyle[(property == 'float' || property == 'cssFloat') ?
+          (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
+            property] = styles[property];
+
+    return element;
+  },
+
+  setOpacity: function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+    return element;
+  },
+
+  getDimensions: function(element) {
+    element = $(element);
+    var display = $(element).getStyle('display');
+    if (display != 'none' && display != null) // Safari bug
+      return {width: element.offsetWidth, height: element.offsetHeight};
+
+    // All *Width and *Height properties give 0 on elements with display none,
+    // so enable the element temporarily
+    var els = element.style;
+    var originalVisibility = els.visibility;
+    var originalPosition = els.position;
+    var originalDisplay = els.display;
+    els.visibility = 'hidden';
+    els.position = 'absolute';
+    els.display = 'block';
+    var originalWidth = element.clientWidth;
+    var originalHeight = element.clientHeight;
+    els.display = originalDisplay;
+    els.position = originalPosition;
+    els.visibility = originalVisibility;
+    return {width: originalWidth, height: originalHeight};
+  },
+
+  makePositioned: function(element) {
+    element = $(element);
+    var pos = Element.getStyle(element, 'position');
+    if (pos == 'static' || !pos) {
+      element._madePositioned = true;
+      element.style.position = 'relative';
+      // Opera returns the offset relative to the positioning context, when an
+      // element is position relative but top and left have not been defined
+      if (window.opera) {
+        element.style.top = 0;
+        element.style.left = 0;
+      }
+    }
+    return element;
+  },
+
+  undoPositioned: function(element) {
+    element = $(element);
+    if (element._madePositioned) {
+      element._madePositioned = undefined;
+      element.style.position =
+        element.style.top =
+        element.style.left =
+        element.style.bottom =
+        element.style.right = '';
+    }
+    return element;
+  },
+
+  makeClipping: function(element) {
+    element = $(element);
+    if (element._overflow) return element;
+    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
+    if (element._overflow !== 'hidden')
+      element.style.overflow = 'hidden';
+    return element;
+  },
+
+  undoClipping: function(element) {
+    element = $(element);
+    if (!element._overflow) return element;
+    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+    element._overflow = null;
+    return element;
+  },
+
+  cumulativeOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+    } while (element);
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  positionedOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      element = element.offsetParent;
+      if (element) {
+        if (element.tagName == 'BODY') break;
+        var p = Element.getStyle(element, 'position');
+        if (p == 'relative' || p == 'absolute') break;
+      }
+    } while (element);
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  absolutize: function(element) {
+    element = $(element);
+    if (element.getStyle('position') == 'absolute') return;
+    // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+    var offsets = element.positionedOffset();
+    var top     = offsets[1];
+    var left    = offsets[0];
+    var width   = element.clientWidth;
+    var height  = element.clientHeight;
+
+    element._originalLeft   = left - parseFloat(element.style.left  || 0);
+    element._originalTop    = top  - parseFloat(element.style.top || 0);
+    element._originalWidth  = element.style.width;
+    element._originalHeight = element.style.height;
+
+    element.style.position = 'absolute';
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.width  = width + 'px';
+    element.style.height = height + 'px';
+    return element;
+  },
+
+  relativize: function(element) {
+    element = $(element);
+    if (element.getStyle('position') == 'relative') return;
+    // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+    element.style.position = 'relative';
+    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
+    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+    element.style.top    = top + 'px';
+    element.style.left   = left + 'px';
+    element.style.height = element._originalHeight;
+    element.style.width  = element._originalWidth;
+    return element;
+  },
+
+  cumulativeScrollOffset: function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.scrollTop  || 0;
+      valueL += element.scrollLeft || 0;
+      element = element.parentNode;
+    } while (element);
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  getOffsetParent: function(element) {
+    if (element.offsetParent) return $(element.offsetParent);
+    if (element == document.body) return $(element);
+
+    while ((element = element.parentNode) && element != document.body)
+      if (Element.getStyle(element, 'position') != 'static')
+        return $(element);
+
+    return $(document.body);
+  },
+
+  viewportOffset: function(forElement) {
+    var valueT = 0, valueL = 0;
+
+    var element = forElement;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+
+      // Safari fix
+      if (element.offsetParent == document.body &&
+        Element.getStyle(element, 'position') == 'absolute') break;
+
+    } while (element = element.offsetParent);
+
+    element = forElement;
+    do {
+      if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
+        valueT -= element.scrollTop  || 0;
+        valueL -= element.scrollLeft || 0;
+      }
+    } while (element = element.parentNode);
+
+    return Element._returnOffset(valueL, valueT);
+  },
+
+  clonePosition: function(element, source) {
+    var options = Object.extend({
+      setLeft:    true,
+      setTop:     true,
+      setWidth:   true,
+      setHeight:  true,
+      offsetTop:  0,
+      offsetLeft: 0
+    }, arguments[2] || { });
+
+    // find page position of source
+    source = $(source);
+    var p = source.viewportOffset();
+
+    // find coordinate system to use
+    element = $(element);
+    var delta = [0, 0];
+    var parent = null;
+    // delta [0,0] will do fine with position: fixed elements,
+    // position:absolute needs offsetParent deltas
+    if (Element.getStyle(element, 'position') == 'absolute') {
+      parent = element.getOffsetParent();
+      delta = parent.viewportOffset();
+    }
+
+    // correct by body offsets (fixes Safari)
+    if (parent == document.body) {
+      delta[0] -= document.body.offsetLeft;
+      delta[1] -= document.body.offsetTop;
+    }
+
+    // set position
+    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
+    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
+    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
+    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
+    return element;
+  }
+};
+
+Element.Methods.identify.counter = 1;
+
+Object.extend(Element.Methods, {
+  getElementsBySelector: Element.Methods.select,
+  childElements: Element.Methods.immediateDescendants
+});
+
+Element._attributeTranslations = {
+  write: {
+    names: {
+      className: 'class',
+      htmlFor:   'for'
+    },
+    values: { }
+  }
+};
+
+
+if (!document.createRange || Prototype.Browser.Opera) {
+  Element.Methods.insert = function(element, insertions) {
+    element = $(element);
+
+    if (Object.isString(insertions) || Object.isNumber(insertions) ||
+        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+          insertions = { bottom: insertions };
+
+    var t = Element._insertionTranslations, content, position, pos, tagName;
+
+    for (position in insertions) {
+      content  = insertions[position];
+      position = position.toLowerCase();
+      pos      = t[position];
+
+      if (content && content.toElement) content = content.toElement();
+      if (Object.isElement(content)) {
+        pos.insert(element, content);
+        continue;
+      }
+
+      content = Object.toHTML(content);
+      tagName = ((position == 'before' || position == 'after')
+        ? element.parentNode : element).tagName.toUpperCase();
+
+      if (t.tags[tagName]) {
+        var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+        if (position == 'top' || position == 'after') fragments.reverse();
+        fragments.each(pos.insert.curry(element));
+      }
+      else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
+
+      content.evalScripts.bind(content).defer();
+    }
+
+    return element;
+  };
+}
+
+if (Prototype.Browser.Opera) {
+  Element.Methods._getStyle = Element.Methods.getStyle;
+  Element.Methods.getStyle = function(element, style) {
+    switch(style) {
+      case 'left':
+      case 'top':
+      case 'right':
+      case 'bottom':
+        if (Element._getStyle(element, 'position') == 'static') return null;
+      default: return Element._getStyle(element, style);
+    }
+  };
+  Element.Methods._readAttribute = Element.Methods.readAttribute;
+  Element.Methods.readAttribute = function(element, attribute) {
+    if (attribute == 'title') return element.title;
+    return Element._readAttribute(element, attribute);
+  };
+}
+
+else if (Prototype.Browser.IE) {
+  $w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
+    Element.Methods[method] = Element.Methods[method].wrap(
+      function(proceed, element) {
+        element = $(element);
+        var position = element.getStyle('position');
+        if (position != 'static') return proceed(element);
+        element.setStyle({ position: 'relative' });
+        var value = proceed(element);
+        element.setStyle({ position: position });
+        return value;
+      }
+    );
+  });
+
+  Element.Methods.getStyle = function(element, style) {
+    element = $(element);
+    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+    var value = element.style[style];
+    if (!value && element.currentStyle) value = element.currentStyle[style];
+
+    if (style == 'opacity') {
+      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+        if (value[1]) return parseFloat(value[1]) / 100;
+      return 1.0;
+    }
+
+    if (value == 'auto') {
+      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+        return element['offset' + style.capitalize()] + 'px';
+      return null;
+    }
+    return value;
+  };
+
+  Element.Methods.setOpacity = function(element, value) {
+    function stripAlpha(filter){
+      return filter.replace(/alpha\([^\)]*\)/gi,'');
+    }
+    element = $(element);
+    var currentStyle = element.currentStyle;
+    if ((currentStyle && !currentStyle.hasLayout) ||
+      (!currentStyle && element.style.zoom == 'normal'))
+        element.style.zoom = 1;
+
+    var filter = element.getStyle('filter'), style = element.style;
+    if (value == 1 || value === '') {
+      (filter = stripAlpha(filter)) ?
+        style.filter = filter : style.removeAttribute('filter');
+      return element;
+    } else if (value < 0.00001) value = 0;
+    style.filter = stripAlpha(filter) +
+      'alpha(opacity=' + (value * 100) + ')';
+    return element;
+  };
+
+  Element._attributeTranslations = {
+    read: {
+      names: {
+        'class': 'className',
+        'for':   'htmlFor'
+      },
+      values: {
+        _getAttr: function(element, attribute) {
+          return element.getAttribute(attribute, 2);
+        },
+        _getAttrNode: function(element, attribute) {
+          var node = element.getAttributeNode(attribute);
+          return node ? node.value : "";
+        },
+        _getEv: function(element, attribute) {
+          var attribute = element.getAttribute(attribute);
+          return attribute ? attribute.toString().slice(23, -2) : null;
+        },
+        _flag: function(element, attribute) {
+          return $(element).hasAttribute(attribute) ? attribute : null;
+        },
+        style: function(element) {
+          return element.style.cssText.toLowerCase();
+        },
+        title: function(element) {
+          return element.title;
+        }
+      }
+    }
+  };
+
+  Element._attributeTranslations.write = {
+    names: Object.clone(Element._attributeTranslations.read.names),
+    values: {
+      checked: function(element, value) {
+        element.checked = !!value;
+      },
+
+      style: function(element, value) {
+        element.style.cssText = value ? value : '';
+      }
+    }
+  };
+
+  Element._attributeTranslations.has = {};
+
+  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
+      'encType maxLength readOnly longDesc').each(function(attr) {
+    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
+    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
+  });
+
+  (function(v) {
+    Object.extend(v, {
+      href:        v._getAttr,
+      src:         v._getAttr,
+      type:        v._getAttr,
+      action:      v._getAttrNode,
+      disabled:    v._flag,
+      checked:     v._flag,
+      readonly:    v._flag,
+      multiple:    v._flag,
+      onload:      v._getEv,
+      onunload:    v._getEv,
+      onclick:     v._getEv,
+      ondblclick:  v._getEv,
+      onmousedown: v._getEv,
+      onmouseup:   v._getEv,
+      onmouseover: v._getEv,
+      onmousemove: v._getEv,
+      onmouseout:  v._getEv,
+      onfocus:     v._getEv,
+      onblur:      v._getEv,
+      onkeypress:  v._getEv,
+      onkeydown:   v._getEv,
+      onkeyup:     v._getEv,
+      onsubmit:    v._getEv,
+      onreset:     v._getEv,
+      onselect:    v._getEv,
+      onchange:    v._getEv
+    });
+  })(Element._attributeTranslations.read.values);
+}
+
+else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1) ? 0.999999 :
+      (value === '') ? '' : (value < 0.00001) ? 0 : value;
+    return element;
+  };
+}
+
+else if (Prototype.Browser.WebKit) {
+  Element.Methods.setOpacity = function(element, value) {
+    element = $(element);
+    element.style.opacity = (value == 1 || value === '') ? '' :
+      (value < 0.00001) ? 0 : value;
+
+    if (value == 1)
+      if(element.tagName == 'IMG' && element.width) {
+        element.width++; element.width--;
+      } else try {
+        var n = document.createTextNode(' ');
+        element.appendChild(n);
+        element.removeChild(n);
+      } catch (e) { }
+
+    return element;
+  };
+
+  // Safari returns margins on body which is incorrect if the child is absolutely
+  // positioned.  For performance reasons, redefine Position.cumulativeOffset for
+  // KHTML/WebKit only.
+  Element.Methods.cumulativeOffset = function(element) {
+    var valueT = 0, valueL = 0;
+    do {
+      valueT += element.offsetTop  || 0;
+      valueL += element.offsetLeft || 0;
+      if (element.offsetParent == document.body)
+        if (Element.getStyle(element, 'position') == 'absolute') break;
+
+      element = element.offsetParent;
+    } while (element);
+
+    return Element._returnOffset(valueL, valueT);
+  };
+}
+
+if (Prototype.Browser.IE || Prototype.Browser.Opera) {
+  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
+  Element.Methods.update = function(element, content) {
+    element = $(element);
+
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) return element.update().insert(content);
+
+    content = Object.toHTML(content);
+    var tagName = element.tagName.toUpperCase();
+
+    if (tagName in Element._insertionTranslations.tags) {
+      $A(element.childNodes).each(function(node) { element.removeChild(node) });
+      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+        .each(function(node) { element.appendChild(node) });
+    }
+    else element.innerHTML = content.stripScripts();
+
+    content.evalScripts.bind(content).defer();
+    return element;
+  };
+}
+
+if (document.createElement('div').outerHTML) {
+  Element.Methods.replace = function(element, content) {
+    element = $(element);
+
+    if (content && content.toElement) content = content.toElement();
+    if (Object.isElement(content)) {
+      element.parentNode.replaceChild(content, element);
+      return element;
+    }
+
+    content = Object.toHTML(content);
+    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+    if (Element._insertionTranslations.tags[tagName]) {
+      var nextSibling = element.next();
+      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+      parent.removeChild(element);
+      if (nextSibling)
+        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
+      else
+        fragments.each(function(node) { parent.appendChild(node) });
+    }
+    else element.outerHTML = content.stripScripts();
+
+    content.evalScripts.bind(content).defer();
+    return element;
+  };
+}
+
+Element._returnOffset = function(l, t) {
+  var result = [l, t];
+  result.left = l;
+  result.top = t;
+  return result;
+};
+
+Element._getContentFromAnonymousElement = function(tagName, html) {
+  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
+  div.innerHTML = t[0] + html + t[1];
+  t[2].times(function() { div = div.firstChild });
+  return $A(div.childNodes);
+};
+
+Element._insertionTranslations = {
+  before: {
+    adjacency: 'beforeBegin',
+    insert: function(element, node) {
+      element.parentNode.insertBefore(node, element);
+    },
+    initializeRange: function(element, range) {
+      range.setStartBefore(element);
+    }
+  },
+  top: {
+    adjacency: 'afterBegin',
+    insert: function(element, node) {
+      element.insertBefore(node, element.firstChild);
+    },
+    initializeRange: function(element, range) {
+      range.selectNodeContents(element);
+      range.collapse(true);
+    }
+  },
+  bottom: {
+    adjacency: 'beforeEnd',
+    insert: function(element, node) {
+      element.appendChild(node);
+    }
+  },
+  after: {
+    adjacency: 'afterEnd',
+    insert: function(element, node) {
+      element.parentNode.insertBefore(node, element.nextSibling);
+    },
+    initializeRange: function(element, range) {
+      range.setStartAfter(element);
+    }
+  },
+  tags: {
+    TABLE:  ['<table>',                '</table>',                   1],
+    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
+    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
+    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
+    SELECT: ['<select>',               '</select>',                  1]
+  }
+};
+
+(function() {
+  this.bottom.initializeRange = this.top.initializeRange;
+  Object.extend(this.tags, {
+    THEAD: this.tags.TBODY,
+    TFOOT: this.tags.TBODY,
+    TH:    this.tags.TD
+  });
+}).call(Element._insertionTranslations);
+
+Element.Methods.Simulated = {
+  hasAttribute: function(element, attribute) {
+    attribute = Element._attributeTranslations.has[attribute] || attribute;
+    var node = $(element).getAttributeNode(attribute);
+    return node && node.specified;
+  }
+};
+
+Element.Methods.ByTag = { };
+
+Object.extend(Element, Element.Methods);
+
+if (!Prototype.BrowserFeatures.ElementExtensions &&
+    document.createElement('div').__proto__) {
+  window.HTMLElement = { };
+  window.HTMLElement.prototype = document.createElement('div').__proto__;
+  Prototype.BrowserFeatures.ElementExtensions = true;
+}
+
+Element.extend = (function() {
+  if (Prototype.BrowserFeatures.SpecificElementExtensions)
+    return Prototype.K;
+
+  var Methods = { }, ByTag = Element.Methods.ByTag;
+
+  var extend = Object.extend(function(element) {
+    if (!element || element._extendedByPrototype ||
+        element.nodeType != 1 || element == window) return element;
+
+    var methods = Object.clone(Methods),
+      tagName = element.tagName, property, value;
+
+    // extend methods for specific tags
+    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+    for (property in methods) {
+      value = methods[property];
+      if (Object.isFunction(value) && !(property in element))
+        element[property] = value.methodize();
+    }
+
+    element._extendedByPrototype = Prototype.emptyFunction;
+    return element;
+
+  }, {
+    refresh: function() {
+      // extend methods for all tags (Safari doesn't need this)
+      if (!Prototype.BrowserFeatures.ElementExtensions) {
+        Object.extend(Methods, Element.Methods);
+        Object.extend(Methods, Element.Methods.Simulated);
+      }
+    }
+  });
+
+  extend.refresh();
+  return extend;
+})();
+
+Element.hasAttribute = function(element, attribute) {
+  if (element.hasAttribute) return element.hasAttribute(attribute);
+  return Element.Methods.Simulated.hasAttribute(element, attribute);
+};
+
+Element.addMethods = function(methods) {
+  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+  if (!methods) {
+    Object.extend(Form, Form.Methods);
+    Object.extend(Form.Element, Form.Element.Methods);
+    Object.extend(Element.Methods.ByTag, {
+      "FORM":     Object.clone(Form.Methods),
+      "INPUT":    Object.clone(Form.Element.Methods),
+      "SELECT":   Object.clone(Form.Element.Methods),
+      "TEXTAREA": Object.clone(Form.Element.Methods)
+    });
+  }
+
+  if (arguments.length == 2) {
+    var tagName = methods;
+    methods = arguments[1];
+  }
+
+  if (!tagName) Object.extend(Element.Methods, methods || { });
+  else {
+    if (Object.isArray(tagName)) tagName.each(extend);
+    else extend(tagName);
+  }
+
+  function extend(tagName) {
+    tagName = tagName.toUpperCase();
+    if (!Element.Methods.ByTag[tagName])
+      Element.Methods.ByTag[tagName] = { };
+    Object.extend(Element.Methods.ByTag[tagName], methods);
+  }
+
+  function copy(methods, destination, onlyIfAbsent) {
+    onlyIfAbsent = onlyIfAbsent || false;
+    for (var property in methods) {
+      var value = methods[property];
+      if (!Object.isFunction(value)) continue;
+      if (!onlyIfAbsent || !(property in destination))
+        destination[property] = value.methodize();
+    }
+  }
+
+  function findDOMClass(tagName) {
+    var klass;
+    var trans = {
+      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+      "FrameSet", "IFRAME": "IFrame"
+    };
+    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName + 'Element';
+    if (window[klass]) return window[klass];
+    klass = 'HTML' + tagName.capitalize() + 'Element';
+    if (window[klass]) return window[klass];
+
+    window[klass] = { };
+    window[klass].prototype = document.createElement(tagName).__proto__;
+    return window[klass];
+  }
+
+  if (F.ElementExtensions) {
+    copy(Element.Methods, HTMLElement.prototype);
+    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+  }
+
+  if (F.SpecificElementExtensions) {
+    for (var tag in Element.Methods.ByTag) {
+      var klass = findDOMClass(tag);
+      if (Object.isUndefined(klass)) continue;
+      copy(T[tag], klass.prototype);
+    }
+  }
+
+  Object.extend(Element, Element.Methods);
+  delete Element.ByTag;
+
+  if (Element.extend.refresh) Element.extend.refresh();
+  Element.cache = { };
+};
+
+document.viewport = {
+  getDimensions: function() {
+    var dimensions = { };
+    $w('width height').each(function(d) {
+      var D = d.capitalize();
+      dimensions[d] = self['inner' + D] ||
+       (document.documentElement['client' + D] || document.body['client' + D]);
+    });
+    return dimensions;
+  },
+
+  getWidth: function() {
+    return this.getDimensions().width;
+  },
+
+  getHeight: function() {
+    return this.getDimensions().height;
+  },
+
+  getScrollOffsets: function() {
+    return Element._returnOffset(
+      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
+      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
+  }
+};
+/* Portions of the Selector class are derived from Jack Slocumâs DomQuery,
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
+ * license.  Please see http://www.yui-ext.com/ for more information. */
+
+var Selector = Class.create({
+  initialize: function(expression) {
+    this.expression = expression.strip();
+    this.compileMatcher();
+  },
+
+  compileMatcher: function() {
+    // Selectors with namespaced attributes can't use the XPath version
+    if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
+      return this.compileXPathMatcher();
+
+    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
+        c = Selector.criteria, le, p, m;
+
+    if (Selector._cache[e]) {
+      this.matcher = Selector._cache[e];
+      return;
+    }
+
+    this.matcher = ["this.matcher = function(root) {",
+                    "var r = root, h = Selector.handlers, c = false, n;"];
+
+    while (e && le != e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        p = ps[i];
+        if (m = e.match(p)) {
+          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
+    	      new Template(c[i]).evaluate(m));
+          e = e.replace(m[0], '');
+          break;
+        }
+      }
+    }
+
+    this.matcher.push("return h.unique(n);\n}");
+    eval(this.matcher.join('\n'));
+    Selector._cache[this.expression] = this.matcher;
+  },
+
+  compileXPathMatcher: function() {
+    var e = this.expression, ps = Selector.patterns,
+        x = Selector.xpath, le, m;
+
+    if (Selector._cache[e]) {
+      this.xpath = Selector._cache[e]; return;
+    }
+
+    this.matcher = ['.//*'];
+    while (e && le != e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        if (m = e.match(ps[i])) {
+          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
+            new Template(x[i]).evaluate(m));
+          e = e.replace(m[0], '');
+          break;
+        }
+      }
+    }
+
+    this.xpath = this.matcher.join('');
+    Selector._cache[this.expression] = this.xpath;
+  },
+
+  findElements: function(root) {
+    root = root || document;
+    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
+    return this.matcher(root);
+  },
+
+  match: function(element) {
+    this.tokens = [];
+
+    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
+    var le, p, m;
+
+    while (e && le !== e && (/\S/).test(e)) {
+      le = e;
+      for (var i in ps) {
+        p = ps[i];
+        if (m = e.match(p)) {
+          // use the Selector.assertions methods unless the selector
+          // is too complex.
+          if (as[i]) {
+            this.tokens.push([i, Object.clone(m)]);
+            e = e.replace(m[0], '');
+          } else {
+            // reluctantly do a document-wide search
+            // and look for a match in the array
+            return this.findElements(document).include(element);
+          }
+        }
+      }
+    }
+
+    var match = true, name, matches;
+    for (var i = 0, token; token = this.tokens[i]; i++) {
+      name = token[0], matches = token[1];
+      if (!Selector.assertions[name](element, matches)) {
+        match = false; break;
+      }
+    }
+
+    return match;
+  },
+
+  toString: function() {
+    return this.expression;
+  },
+
+  inspect: function() {
+    return "#<Selector:" + this.expression.inspect() + ">";
+  }
+});
+
+Object.extend(Selector, {
+  _cache: { },
+
+  xpath: {
+    descendant:   "//*",
+    child:        "/*",
+    adjacent:     "/following-sibling::*[1]",
+    laterSibling: '/following-sibling::*',
+    tagName:      function(m) {
+      if (m[1] == '*') return '';
+      return "[local-name()='" + m[1].toLowerCase() +
+             "' or local-name()='" + m[1].toUpperCase() + "']";
+    },
+    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+    id:           "[@id='#{1}']",
+    attrPresence: "[@#{1}]",
+    attr: function(m) {
+      m[3] = m[5] || m[6];
+      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+    },
+    pseudo: function(m) {
+      var h = Selector.xpath.pseudos[m[1]];
+      if (!h) return '';
+      if (Object.isFunction(h)) return h(m);
+      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+    },
+    operators: {
+      '=':  "[@#{1}='#{3}']",
+      '!=': "[@#{1}!='#{3}']",
+      '^=': "[starts-with(@#{1}, '#{3}')]",
+      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
+      '*=': "[contains(@#{1}, '#{3}')]",
+      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
+      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+    },
+    pseudos: {
+      'first-child': '[not(preceding-sibling::*)]',
+      'last-child':  '[not(following-sibling::*)]',
+      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
+      'empty':       "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
+      'checked':     "[@checked]",
+      'disabled':    "[@disabled]",
+      'enabled':     "[not(@disabled)]",
+      'not': function(m) {
+        var e = m[6], p = Selector.patterns,
+            x = Selector.xpath, le, m, v;
+
+        var exclusion = [];
+        while (e && le != e && (/\S/).test(e)) {
+          le = e;
+          for (var i in p) {
+            if (m = e.match(p[i])) {
+              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
+              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+              e = e.replace(m[0], '');
+              break;
+            }
+          }
+        }
+        return "[not(" + exclusion.join(" and ") + ")]";
+      },
+      'nth-child':      function(m) {
+        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+      },
+      'nth-last-child': function(m) {
+        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+      },
+      'nth-of-type':    function(m) {
+        return Selector.xpath.pseudos.nth("position() ", m);
+      },
+      'nth-last-of-type': function(m) {
+        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+      },
+      'first-of-type':  function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+      },
+      'last-of-type':   function(m) {
+        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+      },
+      'only-of-type':   function(m) {
+        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+      },
+      nth: function(fragment, m) {
+        var mm, formula = m[6], predicate;
+        if (formula == 'even') formula = '2n+0';
+        if (formula == 'odd')  formula = '2n+1';
+        if (mm = formula.match(/^(\d+)$/)) // digit only
+          return '[' + fragment + "= " + mm[1] + ']';
+        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+          if (mm[1] == "-") mm[1] = -1;
+          var a = mm[1] ? Number(mm[1]) : 1;
+          var b = mm[2] ? Number(mm[2]) : 0;
+          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+          "((#{fragment} - #{b}) div #{a} >= 0)]";
+          return new Template(predicate).evaluate({
+            fragment: fragment, a: a, b: b });
+        }
+      }
+    }
+  },
+
+  criteria: {
+    tagName:      'n = h.tagName(n, r, "#{1}", c);   c = false;',
+    className:    'n = h.className(n, r, "#{1}", c); c = false;',
+    id:           'n = h.id(n, r, "#{1}", c);        c = false;',
+    attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
+    attr: function(m) {
+      m[3] = (m[5] || m[6]);
+      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
+    },
+    pseudo: function(m) {
+      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+    },
+    descendant:   'c = "descendant";',
+    child:        'c = "child";',
+    adjacent:     'c = "adjacent";',
+    laterSibling: 'c = "laterSibling";'
+  },
+
+  patterns: {
+    // combinators must be listed first
+    // (and descendant needs to be last combinator)
+    laterSibling: /^\s*~\s*/,
+    child:        /^\s*>\s*/,
+    adjacent:     /^\s*\+\s*/,
+    descendant:   /^\s/,
+
+    // selectors follow
+    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
+    id:           /^#([\w\-\*]+)(\b|$)/,
+    className:    /^\.([\w\-\*]+)(\b|$)/,
+    pseudo:       /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s)|(?=:))/,
+    attrPresence: /^\[([\w]+)\]/,
+    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
+  },
+
+  // for Selector.match and Element#match
+  assertions: {
+    tagName: function(element, matches) {
+      return matches[1].toUpperCase() == element.tagName.toUpperCase();
+    },
+
+    className: function(element, matches) {
+      return Element.hasClassName(element, matches[1]);
+    },
+
+    id: function(element, matches) {
+      return element.id === matches[1];
+    },
+
+    attrPresence: function(element, matches) {
+      return Element.hasAttribute(element, matches[1]);
+    },
+
+    attr: function(element, matches) {
+      var nodeValue = Element.readAttribute(element, matches[1]);
+      return Selector.operators[matches[2]](nodeValue, matches[3]);
+    }
+  },
+
+  handlers: {
+    // UTILITY FUNCTIONS
+    // joins two collections
+    concat: function(a, b) {
+      for (var i = 0, node; node = b[i]; i++)
+        a.push(node);
+      return a;
+    },
+
+    // marks an array of nodes for counting
+    mark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._counted = true;
+      return nodes;
+    },
+
+    unmark: function(nodes) {
+      for (var i = 0, node; node = nodes[i]; i++)
+        node._counted = undefined;
+      return nodes;
+    },
+
+    // mark each child node with its position (for nth calls)
+    // "ofType" flag indicates whether we're indexing for nth-of-type
+    // rather than nth-child
+    index: function(parentNode, reverse, ofType) {
+      parentNode._counted = true;
+      if (reverse) {
+        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+          var node = nodes[i];
+          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+        }
+      } else {
+        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+          if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
+      }
+    },
+
+    // filters out duplicates and extends all nodes
+    unique: function(nodes) {
+      if (nodes.length == 0) return nodes;
+      var results = [], n;
+      for (var i = 0, l = nodes.length; i < l; i++)
+        if (!(n = nodes[i])._counted) {
+          n._counted = true;
+          results.push(Element.extend(n));
+        }
+      return Selector.handlers.unmark(results);
+    },
+
+    // COMBINATOR FUNCTIONS
+    descendant: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, node.getElementsByTagName('*'));
+      return results;
+    },
+
+    child: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
+          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+      }
+      return results;
+    },
+
+    adjacent: function(nodes) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        var next = this.nextElementSibling(node);
+        if (next) results.push(next);
+      }
+      return results;
+    },
+
+    laterSibling: function(nodes) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        h.concat(results, Element.nextSiblings(node));
+      return results;
+    },
+
+    nextElementSibling: function(node) {
+      while (node = node.nextSibling)
+	      if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    previousElementSibling: function(node) {
+      while (node = node.previousSibling)
+        if (node.nodeType == 1) return node;
+      return null;
+    },
+
+    // TOKEN FUNCTIONS
+    tagName: function(nodes, root, tagName, combinator) {
+      tagName = tagName.toUpperCase();
+      var results = [], h = Selector.handlers;
+      if (nodes) {
+        if (combinator) {
+          // fastlane for ordinary descendant combinators
+          if (combinator == "descendant") {
+            for (var i = 0, node; node = nodes[i]; i++)
+              h.concat(results, node.getElementsByTagName(tagName));
+            return results;
+          } else nodes = this[combinator](nodes);
+          if (tagName == "*") return nodes;
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.tagName.toUpperCase() == tagName) results.push(node);
+        return results;
+      } else return root.getElementsByTagName(tagName);
+    },
+
+    id: function(nodes, root, id, combinator) {
+      var targetNode = $(id), h = Selector.handlers;
+      if (!targetNode) return [];
+      if (!nodes && root == document) return [targetNode];
+      if (nodes) {
+        if (combinator) {
+          if (combinator == 'child') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (targetNode.parentNode == node) return [targetNode];
+          } else if (combinator == 'descendant') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Element.descendantOf(targetNode, node)) return [targetNode];
+          } else if (combinator == 'adjacent') {
+            for (var i = 0, node; node = nodes[i]; i++)
+              if (Selector.handlers.previousElementSibling(targetNode) == node)
+                return [targetNode];
+          } else nodes = h[combinator](nodes);
+        }
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node == targetNode) return [targetNode];
+        return [];
+      }
+      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+    },
+
+    className: function(nodes, root, className, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      return Selector.handlers.byClassName(nodes, root, className);
+    },
+
+    byClassName: function(nodes, root, className) {
+      if (!nodes) nodes = Selector.handlers.descendant([root]);
+      var needle = ' ' + className + ' ';
+      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+        nodeClassName = node.className;
+        if (nodeClassName.length == 0) continue;
+        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+          results.push(node);
+      }
+      return results;
+    },
+
+    attrPresence: function(nodes, root, attr) {
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      var results = [];
+      for (var i = 0, node; node = nodes[i]; i++)
+        if (Element.hasAttribute(node, attr)) results.push(node);
+      return results;
+    },
+
+    attr: function(nodes, root, attr, value, operator) {
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      var handler = Selector.operators[operator], results = [];
+      for (var i = 0, node; node = nodes[i]; i++) {
+        var nodeValue = Element.readAttribute(node, attr);
+        if (nodeValue === null) continue;
+        if (handler(nodeValue, value)) results.push(node);
+      }
+      return results;
+    },
+
+    pseudo: function(nodes, name, value, root, combinator) {
+      if (nodes && combinator) nodes = this[combinator](nodes);
+      if (!nodes) nodes = root.getElementsByTagName("*");
+      return Selector.pseudos[name](nodes, value, root);
+    }
+  },
+
+  pseudos: {
+    'first-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.previousElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'last-child': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        if (Selector.handlers.nextElementSibling(node)) continue;
+          results.push(node);
+      }
+      return results;
+    },
+    'only-child': function(nodes, value, root) {
+      var h = Selector.handlers;
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+          results.push(node);
+      return results;
+    },
+    'nth-child':        function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root);
+    },
+    'nth-last-child':   function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true);
+    },
+    'nth-of-type':      function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, false, true);
+    },
+    'nth-last-of-type': function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, formula, root, true, true);
+    },
+    'first-of-type':    function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, false, true);
+    },
+    'last-of-type':     function(nodes, formula, root) {
+      return Selector.pseudos.nth(nodes, "1", root, true, true);
+    },
+    'only-of-type':     function(nodes, formula, root) {
+      var p = Selector.pseudos;
+      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+    },
+
+    // handles the an+b logic
+    getIndices: function(a, b, total) {
+      if (a == 0) return b > 0 ? [b] : [];
+      return $R(1, total).inject([], function(memo, i) {
+        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+        return memo;
+      });
+    },
+
+    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+    nth: function(nodes, formula, root, reverse, ofType) {
+      if (nodes.length == 0) return [];
+      if (formula == 'even') formula = '2n+0';
+      if (formula == 'odd')  formula = '2n+1';
+      var h = Selector.handlers, results = [], indexed = [], m;
+      h.mark(nodes);
+      for (var i = 0, node; node = nodes[i]; i++) {
+        if (!node.parentNode._counted) {
+          h.index(node.parentNode, reverse, ofType);
+          indexed.push(node.parentNode);
+        }
+      }
+      if (formula.match(/^\d+$/)) { // just a number
+        formula = Number(formula);
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.nodeIndex == formula) results.push(node);
+      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+        if (m[1] == "-") m[1] = -1;
+        var a = m[1] ? Number(m[1]) : 1;
+        var b = m[2] ? Number(m[2]) : 0;
+        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+          for (var j = 0; j < l; j++)
+            if (node.nodeIndex == indices[j]) results.push(node);
+        }
+      }
+      h.unmark(nodes);
+      h.unmark(indexed);
+      return results;
+    },
+
+    'empty': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++) {
+        // IE treats comments as element nodes
+        if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
+        results.push(node);
+      }
+      return results;
+    },
+
+    'not': function(nodes, selector, root) {
+      var h = Selector.handlers, selectorType, m;
+      var exclusions = new Selector(selector).findElements(root);
+      h.mark(exclusions);
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node._counted) results.push(node);
+      h.unmark(exclusions);
+      return results;
+    },
+
+    'enabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (!node.disabled) results.push(node);
+      return results;
+    },
+
+    'disabled': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.disabled) results.push(node);
+      return results;
+    },
+
+    'checked': function(nodes, value, root) {
+      for (var i = 0, results = [], node; node = nodes[i]; i++)
+        if (node.checked) results.push(node);
+      return results;
+    }
+  },
+
+  operators: {
+    '=':  function(nv, v) { return nv == v; },
+    '!=': function(nv, v) { return nv != v; },
+    '^=': function(nv, v) { return nv.startsWith(v); },
+    '$=': function(nv, v) { return nv.endsWith(v); },
+    '*=': function(nv, v) { return nv.include(v); },
+    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
+    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
+  },
+
+  matchElements: function(elements, expression) {
+    var matches = new Selector(expression).findElements(), h = Selector.handlers;
+    h.mark(matches);
+    for (var i = 0, results = [], element; element = elements[i]; i++)
+      if (element._counted) results.push(element);
+    h.unmark(matches);
+    return results;
+  },
+
+  findElement: function(elements, expression, index) {
+    if (Object.isNumber(expression)) {
+      index = expression; expression = false;
+    }
+    return Selector.matchElements(elements, expression || '*')[index || 0];
+  },
+
+  findChildElements: function(element, expressions) {
+    var exprs = expressions.join(','), expressions = [];
+    exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+      expressions.push(m[1].strip());
+    });
+    var results = [], h = Selector.handlers;
+    for (var i = 0, l = expressions.length, selector; i < l; i++) {
+      selector = new Selector(expressions[i].strip());
+      h.concat(results, selector.findElements(element));
+    }
+    return (l > 1) ? h.unique(results) : results;
+  }
+});
+
+function $$() {
+  return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+  reset: function(form) {
+    $(form).reset();
+    return form;
+  },
+
+  serializeElements: function(elements, options) {
+    if (typeof options != 'object') options = { hash: !!options };
+    else if (options.hash === undefined) options.hash = true;
+    var key, value, submitted = false, submit = options.submit;
+
+    var data = elements.inject({ }, function(result, element) {
+      if (!element.disabled && element.name) {
+        key = element.name; value = $(element).getValue();
+        if (value != null && (element.type != 'submit' || (!submitted &&
+            submit !== false && (!submit || key == submit) && (submitted = true)))) {
+          if (key in result) {
+            // a key is already present; construct an array of values
+            if (!Object.isArray(result[key])) result[key] = [result[key]];
+            result[key].push(value);
+          }
+          else result[key] = value;
+        }
+      }
+      return result;
+    });
+
+    return options.hash ? data : Object.toQueryString(data);
+  }
+};
+
+Form.Methods = {
+  serialize: function(form, options) {
+    return Form.serializeElements(Form.getElements(form), options);
+  },
+
+  getElements: function(form) {
+    return $A($(form).getElementsByTagName('*')).inject([],
+      function(elements, child) {
+        if (Form.Element.Serializers[child.tagName.toLowerCase()])
+          elements.push(Element.extend(child));
+        return elements;
+      }
+    );
+  },
+
+  getInputs: function(form, typeName, name) {
+    form = $(form);
+    var inputs = form.getElementsByTagName('input');
+
+    if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+      var input = inputs[i];
+      if ((typeName && input.type != typeName) || (name && input.name != name))
+        continue;
+      matchingInputs.push(Element.extend(input));
+    }
+
+    return matchingInputs;
+  },
+
+  disable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('disable');
+    return form;
+  },
+
+  enable: function(form) {
+    form = $(form);
+    Form.getElements(form).invoke('enable');
+    return form;
+  },
+
+  findFirstElement: function(form) {
+    var elements = $(form).getElements().findAll(function(element) {
+      return 'hidden' != element.type && !element.disabled;
+    });
+    var firstByIndex = elements.findAll(function(element) {
+      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+    }).sortBy(function(element) { return element.tabIndex }).first();
+
+    return firstByIndex ? firstByIndex : elements.find(function(element) {
+      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+    });
+  },
+
+  focusFirstElement: function(form) {
+    form = $(form);
+    form.findFirstElement().activate();
+    return form;
+  },
+
+  request: function(form, options) {
+    form = $(form), options = Object.clone(options || { });
+
+    var params = options.parameters, action = form.readAttribute('action') || '';
+    if (action.blank()) action = window.location.href;
+    options.parameters = form.serialize(true);
+
+    if (params) {
+      if (Object.isString(params)) params = params.toQueryParams();
+      Object.extend(options.parameters, params);
+    }
+
+    if (form.hasAttribute('method') && !options.method)
+      options.method = form.method;
+
+    return new Ajax.Request(action, options);
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+  focus: function(element) {
+    $(element).focus();
+    return element;
+  },
+
+  select: function(element) {
+    $(element).select();
+    return element;
+  }
+};
+
+Form.Element.Methods = {
+  serialize: function(element) {
+    element = $(element);
+    if (!element.disabled && element.name) {
+      var value = element.getValue();
+      if (value != undefined) {
+        var pair = { };
+        pair[element.name] = value;
+        return Object.toQueryString(pair);
+      }
+    }
+    return '';
+  },
+
+  getValue: function(element) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    return Form.Element.Serializers[method](element);
+  },
+
+  setValue: function(element, value) {
+    element = $(element);
+    var method = element.tagName.toLowerCase();
+    Form.Element.Serializers[method](element, value);
+    return element;
+  },
+
+  clear: function(element) {
+    $(element).value = '';
+    return element;
+  },
+
+  present: function(element) {
+    return $(element).value != '';
+  },
+
+  activate: function(element) {
+    element = $(element);
+    try {
+      element.focus();
+      if (element.select && (element.tagName.toLowerCase() != 'input' ||
+          !['button', 'reset', 'submit'].include(element.type)))
+        element.select();
+    } catch (e) { }
+    return element;
+  },
+
+  disable: function(element) {
+    element = $(element);
+    element.blur();
+    element.disabled = true;
+    return element;
+  },
+
+  enable: function(element) {
+    element = $(element);
+    element.disabled = false;
+    return element;
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+var Field = Form.Element;
+var $F = Form.Element.Methods.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+  input: function(element, value) {
+    switch (element.type.toLowerCase()) {
+      case 'checkbox':
+      case 'radio':
+        return Form.Element.Serializers.inputSelector(element, value);
+      default:
+        return Form.Element.Serializers.textarea(element, value);
+    }
+  },
+
+  inputSelector: function(element, value) {
+    if (value === undefined) return element.checked ? element.value : null;
+    else element.checked = !!value;
+  },
+
+  textarea: function(element, value) {
+    if (value === undefined) return element.value;
+    else element.value = value;
+  },
+
+  select: function(element, index) {
+    if (index === undefined)
+      return this[element.type == 'select-one' ?
+        'selectOne' : 'selectMany'](element);
+    else {
+      var opt, value, single = !Object.isArray(index);
+      for (var i = 0, length = element.length; i < length; i++) {
+        opt = element.options[i];
+        value = this.optionValue(opt);
+        if (single) {
+          if (value == index) {
+            opt.selected = true;
+            return;
+          }
+        }
+        else opt.selected = index.include(value);
+      }
+    }
+  },
+
+  selectOne: function(element) {
+    var index = element.selectedIndex;
+    return index >= 0 ? this.optionValue(element.options[index]) : null;
+  },
+
+  selectMany: function(element) {
+    var values, length = element.length;
+    if (!length) return null;
+
+    for (var i = 0, values = []; i < length; i++) {
+      var opt = element.options[i];
+      if (opt.selected) values.push(this.optionValue(opt));
+    }
+    return values;
+  },
+
+  optionValue: function(opt) {
+    // extend element because hasAttribute may not be native
+    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+  initialize: function($super, element, frequency, callback) {
+    $super(callback, frequency);
+    this.element   = $(element);
+    this.lastValue = this.getValue();
+  },
+
+  execute: function() {
+    var value = this.getValue();
+    if (Object.isString(this.lastValue) && Object.isString(value) ?
+        this.lastValue != value : String(this.lastValue) != String(value)) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  }
+});
+
+Form.Element.Observer = Class.create(Abstract.TimedObserver, {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.Observer = Class.create(Abstract.TimedObserver, {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = Class.create({
+  initialize: function(element, callback) {
+    this.element  = $(element);
+    this.callback = callback;
+
+    this.lastValue = this.getValue();
+    if (this.element.tagName.toLowerCase() == 'form')
+      this.registerFormCallbacks();
+    else
+      this.registerCallback(this.element);
+  },
+
+  onElementEvent: function() {
+    var value = this.getValue();
+    if (this.lastValue != value) {
+      this.callback(this.element, value);
+      this.lastValue = value;
+    }
+  },
+
+  registerFormCallbacks: function() {
+    Form.getElements(this.element).each(this.registerCallback, this);
+  },
+
+  registerCallback: function(element) {
+    if (element.type) {
+      switch (element.type.toLowerCase()) {
+        case 'checkbox':
+        case 'radio':
+          Event.observe(element, 'click', this.onElementEvent.bind(this));
+          break;
+        default:
+          Event.observe(element, 'change', this.onElementEvent.bind(this));
+          break;
+      }
+    }
+  }
+});
+
+Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
+  getValue: function() {
+    return Form.Element.getValue(this.element);
+  }
+});
+
+Form.EventObserver = Class.create(Abstract.EventObserver, {
+  getValue: function() {
+    return Form.serialize(this.element);
+  }
+});
+if (!window.Event) var Event = { };
+
+Object.extend(Event, {
+  KEY_BACKSPACE: 8,
+  KEY_TAB:       9,
+  KEY_RETURN:   13,
+  KEY_ESC:      27,
+  KEY_LEFT:     37,
+  KEY_UP:       38,
+  KEY_RIGHT:    39,
+  KEY_DOWN:     40,
+  KEY_DELETE:   46,
+  KEY_HOME:     36,
+  KEY_END:      35,
+  KEY_PAGEUP:   33,
+  KEY_PAGEDOWN: 34,
+  KEY_INSERT:   45,
+
+  cache: { },
+
+  relatedTarget: function(event) {
+    var element;
+    switch(event.type) {
+      case 'mouseover': element = event.fromElement; break;
+      case 'mouseout':  element = event.toElement;   break;
+      default: return null;
+    }
+    return Element.extend(element);
+  }
+});
+
+Event.Methods = (function() {
+  var isButton;
+
+  if (Prototype.Browser.IE) {
+    var buttonMap = { 0: 1, 1: 4, 2: 2 };
+    isButton = function(event, code) {
+      return event.button == buttonMap[code];
+    };
+
+  } else if (Prototype.Browser.WebKit) {
+    isButton = function(event, code) {
+      switch (code) {
+        case 0: return event.which == 1 && !event.metaKey;
+        case 1: return event.which == 1 && event.metaKey;
+        default: return false;
+      }
+    };
+
+  } else {
+    isButton = function(event, code) {
+      return event.which ? (event.which === code + 1) : (event.button === code);
+    };
+  }
+
+  return {
+    isLeftClick:   function(event) { return isButton(event, 0) },
+    isMiddleClick: function(event) { return isButton(event, 1) },
+    isRightClick:  function(event) { return isButton(event, 2) },
+
+    element: function(event) {
+      var node = Event.extend(event).target;
+      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
+    },
+
+    findElement: function(event, expression) {
+      var element = Event.element(event);
+      return element.match(expression) ? element : element.up(expression);
+    },
+
+    pointer: function(event) {
+      return {
+        x: event.pageX || (event.clientX +
+          (document.documentElement.scrollLeft || document.body.scrollLeft)),
+        y: event.pageY || (event.clientY +
+          (document.documentElement.scrollTop || document.body.scrollTop))
+      };
+    },
+
+    pointerX: function(event) { return Event.pointer(event).x },
+    pointerY: function(event) { return Event.pointer(event).y },
+
+    stop: function(event) {
+      Event.extend(event);
+      event.preventDefault();
+      event.stopPropagation();
+      event.stopped = true;
+    }
+  };
+})();
+
+Event.extend = (function() {
+  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+    m[name] = Event.Methods[name].methodize();
+    return m;
+  });
+
+  if (Prototype.Browser.IE) {
+    Object.extend(methods, {
+      stopPropagation: function() { this.cancelBubble = true },
+      preventDefault:  function() { this.returnValue = false },
+      inspect: function() { return "[object Event]" }
+    });
+
+    return function(event) {
+      if (!event) return false;
+      if (event._extendedByPrototype) return event;
+
+      event._extendedByPrototype = Prototype.emptyFunction;
+      var pointer = Event.pointer(event);
+      Object.extend(event, {
+        target: event.srcElement,
+        relatedTarget: Event.relatedTarget(event),
+        pageX:  pointer.x,
+        pageY:  pointer.y
+      });
+      return Object.extend(event, methods);
+    };
+
+  } else {
+    Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
+    Object.extend(Event.prototype, methods);
+    return Prototype.K;
+  }
+})();
+
+Object.extend(Event, (function() {
+  var cache = Event.cache;
+
+  function getEventID(element) {
+    if (element._eventID) return element._eventID;
+    arguments.callee.id = arguments.callee.id || 1;
+    return element._eventID = ++arguments.callee.id;
+  }
+
+  function getDOMEventName(eventName) {
+    if (eventName && eventName.include(':')) return "dataavailable";
+    return eventName;
+  }
+
+  function getCacheForID(id) {
+    return cache[id] = cache[id] || { };
+  }
+
+  function getWrappersForEventName(id, eventName) {
+    var c = getCacheForID(id);
+    return c[eventName] = c[eventName] || [];
+  }
+
+  function createWrapper(element, eventName, handler) {
+    var id = getEventID(element);
+    var c = getWrappersForEventName(id, eventName);
+    if (c.pluck("handler").include(handler)) return false;
+
+    var wrapper = function(event) {
+      if (!Event || !Event.extend ||
+        (event.eventName && event.eventName != eventName))
+          return false;
+
+      Event.extend(event);
+      handler.call(element, event)
+    };
+
+    wrapper.handler = handler;
+    c.push(wrapper);
+    return wrapper;
+  }
+
+  function findWrapper(id, eventName, handler) {
+    var c = getWrappersForEventName(id, eventName);
+    return c.find(function(wrapper) { return wrapper.handler == handler });
+  }
+
+  function destroyWrapper(id, eventName, handler) {
+    var c = getCacheForID(id);
+    if (!c[eventName]) return false;
+    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
+  }
+
+  function destroyCache() {
+    for (var id in cache)
+      for (var eventName in cache[id])
+        cache[id][eventName] = null;
+  }
+
+  if (window.attachEvent) {
+    window.attachEvent("onunload", destroyCache);
+  }
+
+  return {
+    observe: function(element, eventName, handler) {
+      element = $(element);
+      var name = getDOMEventName(eventName);
+
+      var wrapper = createWrapper(element, eventName, handler);
+      if (!wrapper) return element;
+
+      if (element.addEventListener) {
+        element.addEventListener(name, wrapper, false);
+      } else {
+        element.attachEvent("on" + name, wrapper);
+      }
+
+      return element;
+    },
+
+    stopObserving: function(element, eventName, handler) {
+      element = $(element);
+      var id = getEventID(element), name = getDOMEventName(eventName);
+
+      if (!handler && eventName) {
+        getWrappersForEventName(id, eventName).each(function(wrapper) {
+          element.stopObserving(eventName, wrapper.handler);
+        });
+        return element;
+
+      } else if (!eventName) {
+        Object.keys(getCacheForID(id)).each(function(eventName) {
+          element.stopObserving(eventName);
+        });
+        return element;
+      }
+
+      var wrapper = findWrapper(id, eventName, handler);
+      if (!wrapper) return element;
+
+      if (element.removeEventListener) {
+        element.removeEventListener(name, wrapper, false);
+      } else {
+        element.detachEvent("on" + name, wrapper);
+      }
+
+      destroyWrapper(id, eventName, handler);
+
+      return element;
+    },
+
+    fire: function(element, eventName, memo) {
+      element = $(element);
+      if (element == document && document.createEvent && !element.dispatchEvent)
+        element = document.documentElement;
+
+      if (document.createEvent) {
+        var event = document.createEvent("HTMLEvents");
+        event.initEvent("dataavailable", true, true);
+      } else {
+        var event = document.createEventObject();
+        event.eventType = "ondataavailable";
+      }
+
+      event.eventName = eventName;
+      event.memo = memo || { };
+
+      if (document.createEvent) {
+        element.dispatchEvent(event);
+      } else {
+        element.fireEvent(event.eventType, event);
+      }
+
+      return event;
+    }
+  };
+})());
+
+Object.extend(Event, Event.Methods);
+
+Element.addMethods({
+  fire:          Event.fire,
+  observe:       Event.observe,
+  stopObserving: Event.stopObserving
+});
+
+Object.extend(document, {
+  fire:          Element.Methods.fire.methodize(),
+  observe:       Element.Methods.observe.methodize(),
+  stopObserving: Element.Methods.stopObserving.methodize()
+});
+
+(function() {
+  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+     Matthias Miller, Dean Edwards and John Resig. */
+
+  var timer, fired = false;
+
+  function fireContentLoadedEvent() {
+    if (fired) return;
+    if (timer) window.clearInterval(timer);
+    document.fire("dom:loaded");
+    fired = true;
+  }
+
+  if (document.addEventListener) {
+    if (Prototype.Browser.WebKit) {
+      timer = window.setInterval(function() {
+        if (/loaded|complete/.test(document.readyState))
+          fireContentLoadedEvent();
+      }, 0);
+
+      Event.observe(window, "load", fireContentLoadedEvent);
+
+    } else {
+      document.addEventListener("DOMContentLoaded",
+        fireContentLoadedEvent, false);
+    }
+
+  } else {
+    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
+    $("__onDOMContentLoaded").onreadystatechange = function() {
+      if (this.readyState == "complete") {
+        this.onreadystatechange = null;
+        fireContentLoadedEvent();
+      }
+    };
+  }
+})();
+/*------------------------------- DEPRECATED -------------------------------*/
+
+Hash.toQueryString = Object.toQueryString;
+
+var Toggle = { display: Element.toggle };
+
+Element.Methods.childOf = Element.Methods.descendantOf;
+
+var Insertion = {
+  Before: function(element, content) {
+    return Element.insert(element, {before:content});
+  },
+
+  Top: function(element, content) {
+    return Element.insert(element, {top:content});
+  },
+
+  Bottom: function(element, content) {
+    return Element.insert(element, {bottom:content});
+  },
+
+  After: function(element, content) {
+    return Element.insert(element, {after:content});
+  }
+};
+
+var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+// This should be moved to script.aculo.us; notice the deprecated methods
+// further below, that map to the newer Element methods.
+var Position = {
+  // set to true if needed, warning: firefox performance problems
+  // NOT neeeded for page scrolling, only if draggable contained in
+  // scrollable elements
+  includeScrollOffsets: false,
+
+  // must be called before calling withinIncludingScrolloffset, every time the
+  // page is scrolled
+  prepare: function() {
+    this.deltaX =  window.pageXOffset
+                || document.documentElement.scrollLeft
+                || document.body.scrollLeft
+                || 0;
+    this.deltaY =  window.pageYOffset
+                || document.documentElement.scrollTop
+                || document.body.scrollTop
+                || 0;
+  },
+
+  // caches x/y coordinate pair to use with overlap
+  within: function(element, x, y) {
+    if (this.includeScrollOffsets)
+      return this.withinIncludingScrolloffsets(element, x, y);
+    this.xcomp = x;
+    this.ycomp = y;
+    this.offset = Element.cumulativeOffset(element);
+
+    return (y >= this.offset[1] &&
+            y <  this.offset[1] + element.offsetHeight &&
+            x >= this.offset[0] &&
+            x <  this.offset[0] + element.offsetWidth);
+  },
+
+  withinIncludingScrolloffsets: function(element, x, y) {
+    var offsetcache = Element.cumulativeScrollOffset(element);
+
+    this.xcomp = x + offsetcache[0] - this.deltaX;
+    this.ycomp = y + offsetcache[1] - this.deltaY;
+    this.offset = Element.cumulativeOffset(element);
+
+    return (this.ycomp >= this.offset[1] &&
+            this.ycomp <  this.offset[1] + element.offsetHeight &&
+            this.xcomp >= this.offset[0] &&
+            this.xcomp <  this.offset[0] + element.offsetWidth);
+  },
+
+  // within must be called directly before
+  overlap: function(mode, element) {
+    if (!mode) return 0;
+    if (mode == 'vertical')
+      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+        element.offsetHeight;
+    if (mode == 'horizontal')
+      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+        element.offsetWidth;
+  },
+
+  // Deprecation layer -- use newer Element methods now (1.5.2).
+
+  cumulativeOffset: Element.Methods.cumulativeOffset,
+
+  positionedOffset: Element.Methods.positionedOffset,
+
+  absolutize: function(element) {
+    Position.prepare();
+    return Element.absolutize(element);
+  },
+
+  relativize: function(element) {
+    Position.prepare();
+    return Element.relativize(element);
+  },
+
+  realOffset: Element.Methods.cumulativeScrollOffset,
+
+  offsetParent: Element.Methods.getOffsetParent,
+
+  page: Element.Methods.viewportOffset,
+
+  clone: function(source, target, options) {
+    options = options || { };
+    return Element.clonePosition(target, source, options);
+  }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+  function iter(name) {
+    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+  }
+
+  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+  function(element, className) {
+    className = className.toString().strip();
+    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+  } : function(element, className) {
+    className = className.toString().strip();
+    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+    if (!classNames && !className) return elements;
+
+    var nodes = $(element).getElementsByTagName('*');
+    className = ' ' + className + ' ';
+
+    for (var i = 0, child, cn; child = nodes[i]; i++) {
+      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+          (classNames && classNames.all(function(name) {
+            return !name.toString().blank() && cn.include(' ' + name + ' ');
+          }))))
+        elements.push(Element.extend(child));
+    }
+    return elements;
+  };
+
+  return function(className, parentElement) {
+    return $(parentElement || document.body).getElementsByClassName(className);
+  };
+}(Element.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+  initialize: function(element) {
+    this.element = $(element);
+  },
+
+  _each: function(iterator) {
+    this.element.className.split(/\s+/).select(function(name) {
+      return name.length > 0;
+    })._each(iterator);
+  },
+
+  set: function(className) {
+    this.element.className = className;
+  },
+
+  add: function(classNameToAdd) {
+    if (this.include(classNameToAdd)) return;
+    this.set($A(this).concat(classNameToAdd).join(' '));
+  },
+
+  remove: function(classNameToRemove) {
+    if (!this.include(classNameToRemove)) return;
+    this.set($A(this).without(classNameToRemove).join(' '));
+  },
+
+  toString: function() {
+    return $A(this).join(' ');
+  }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+
+/*--------------------------------------------------------------------------*/
+
+Element.addMethods();
Index: /branches/features/grailsUpgrade/web-app/js/prototype/rico.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/rico.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/rico.js	(revision 875)
@@ -0,0 +1,2691 @@
+/**
+  *
+  *  Copyright 2005 Sabre Airline Solutions
+  *
+  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+  *  file except in compliance with the License. You may obtain a copy of the License at
+  *
+  *         http://www.apache.org/licenses/LICENSE-2.0
+  *
+  *  Unless required by applicable law or agreed to in writing, software distributed under the
+  *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+  *  either express or implied. See the License for the specific language governing permissions
+  *  and limitations under the License.
+  **/
+
+
+//-------------------- rico.js
+var Rico = {
+  Version: '1.1-beta2'
+}
+
+Rico.ArrayExtensions = new Array();
+
+if (Object.prototype.extend) {
+   // in prototype.js...
+   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
+}
+
+if (Array.prototype.push) {
+   // in prototype.js...
+   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
+}
+
+if (!Array.prototype.remove) {
+   Array.prototype.remove = function(dx) {
+      if( isNaN(dx) || dx > this.length )
+         return false;
+      for( var i=0,n=0; i<this.length; i++ )
+         if( i != dx )
+            this[n++]=this[i];
+      this.length-=1;
+   };
+  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
+}
+
+if (!Array.prototype.removeItem) {
+   Array.prototype.removeItem = function(item) {
+      for ( var i = 0 ; i < this.length ; i++ )
+         if ( this[i] == item ) {
+            this.remove(i);
+            break;
+         }
+   };
+  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
+}
+
+if (!Array.prototype.indices) {
+   Array.prototype.indices = function() {
+      var indexArray = new Array();
+      for ( index in this ) {
+         var ignoreThis = false;
+         for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
+            if ( this[index] == Rico.ArrayExtensions[i] ) {
+               ignoreThis = true;
+               break;
+            }
+         }
+         if ( !ignoreThis )
+            indexArray[ indexArray.length ] = index;
+      }
+      return indexArray;
+   }
+  Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
+}
+
+// Create the loadXML method and xml getter for Mozilla
+if ( window.DOMParser &&
+	  window.XMLSerializer &&
+	  window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
+
+   if (!Document.prototype.loadXML) {
+      Document.prototype.loadXML = function (s) {
+         var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
+         while (this.hasChildNodes())
+            this.removeChild(this.lastChild);
+
+         for (var i = 0; i < doc2.childNodes.length; i++) {
+            this.appendChild(this.importNode(doc2.childNodes[i], true));
+         }
+      };
+	}
+
+	Document.prototype.__defineGetter__( "xml",
+	   function () {
+		   return (new XMLSerializer()).serializeToString(this);
+	   }
+	 );
+}
+
+document.getElementsByTagAndClassName = function(tagName, className) {
+  if ( tagName == null )
+     tagName = '*';
+
+  var children = document.getElementsByTagName(tagName) || document.all;
+  var elements = new Array();
+
+  if ( className == null )
+    return children;
+
+  for (var i = 0; i < children.length; i++) {
+    var child = children[i];
+    var classNames = child.className.split(' ');
+    for (var j = 0; j < classNames.length; j++) {
+      if (classNames[j] == className) {
+        elements.push(child);
+        break;
+      }
+    }
+  }
+
+  return elements;
+}
+
+
+//-------------------- ricoAccordion.js
+
+Rico.Accordion = Class.create();
+
+Rico.Accordion.prototype = {
+
+   initialize: function(container, options) {
+      this.container            = $(container);
+      this.lastExpandedTab      = null;
+      this.accordionTabs        = new Array();
+      this.setOptions(options);
+      this._attachBehaviors();
+
+      this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
+
+      // set the initial visual state...
+      for ( var i=1 ; i < this.accordionTabs.length ; i++ )
+      {
+         this.accordionTabs[i].collapse();
+         this.accordionTabs[i].content.style.display = 'none';
+      }
+      this.lastExpandedTab = this.accordionTabs[0];
+      this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
+      this.lastExpandedTab.showExpanded();
+      this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
+   },
+
+   setOptions: function(options) {
+      this.options = {
+         expandedBg          : '#63699c',
+         hoverBg             : '#63699c',
+         collapsedBg         : '#6b79a5',
+         expandedTextColor   : '#ffffff',
+         expandedFontWeight  : 'bold',
+         hoverTextColor      : '#ffffff',
+         collapsedTextColor  : '#ced7ef',
+         collapsedFontWeight : 'normal',
+         hoverTextColor      : '#ffffff',
+         borderColor         : '#1f669b',
+         panelHeight         : 200,
+         onHideTab           : null,
+         onShowTab           : null
+      }.extend(options || {});
+   },
+
+   showTabByIndex: function( anIndex, animate ) {
+      var doAnimate = arguments.length == 1 ? true : animate;
+      this.showTab( this.accordionTabs[anIndex], doAnimate );
+   },
+
+   showTab: function( accordionTab, animate ) {
+
+      var doAnimate = arguments.length == 1 ? true : animate;
+
+      if ( this.options.onHideTab )
+         this.options.onHideTab(this.lastExpandedTab);
+
+      this.lastExpandedTab.showCollapsed(); 
+      var accordion = this;
+      var lastExpandedTab = this.lastExpandedTab;
+
+      this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
+      accordionTab.content.style.display = '';
+
+      accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
+
+      if ( doAnimate ) {
+         new Effect.AccordionSize( this.lastExpandedTab.content,
+                                   accordionTab.content,
+                                   1,
+                                   this.options.panelHeight,
+                                   100, 10,
+                                   { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
+         this.lastExpandedTab = accordionTab;
+      }
+      else {
+         this.lastExpandedTab.content.style.height = "1px";
+         accordionTab.content.style.height = this.options.panelHeight + "px";
+         this.lastExpandedTab = accordionTab;
+         this.showTabDone(lastExpandedTab);
+      }
+   },
+
+   showTabDone: function(collapsedTab) {
+      collapsedTab.content.style.display = 'none';
+      this.lastExpandedTab.showExpanded();
+      if ( this.options.onShowTab )
+         this.options.onShowTab(this.lastExpandedTab);
+   },
+
+   _attachBehaviors: function() {
+      var panels = this._getDirectChildrenByTag(this.container, 'DIV');
+      for ( var i = 0 ; i < panels.length ; i++ ) {
+
+         var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
+         if ( tabChildren.length != 2 )
+            continue; // unexpected
+
+         var tabTitleBar   = tabChildren[0];
+         var tabContentBox = tabChildren[1];
+         this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
+      }
+   },
+
+   _getDirectChildrenByTag: function(e, tagName) {
+      var kids = new Array();
+      var allKids = e.childNodes;
+      for( var i = 0 ; i < allKids.length ; i++ )
+         if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
+            kids.push(allKids[i]);
+      return kids;
+   }
+
+};
+
+Rico.Accordion.Tab = Class.create();
+
+Rico.Accordion.Tab.prototype = {
+
+   initialize: function(accordion, titleBar, content) {
+      this.accordion = accordion;
+      this.titleBar  = titleBar;
+      this.content   = content;
+      this._attachBehaviors();
+   },
+
+   collapse: function() {
+      this.showCollapsed();
+      this.content.style.height = "1px";
+   },
+
+   showCollapsed: function() {
+      this.expanded = false;
+      this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
+      this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
+      this.titleBar.style.fontWeight      = this.accordion.options.collapsedFontWeight;
+      this.content.style.overflow = "hidden";
+   },
+
+   showExpanded: function() {
+      this.expanded = true;
+      this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
+      this.titleBar.style.color           = this.accordion.options.expandedTextColor;
+      this.content.style.overflow         = "visible";
+   },
+
+   titleBarClicked: function(e) {
+      if ( this.accordion.lastExpandedTab == this )
+         return;
+      this.accordion.showTab(this);
+   },
+
+   hover: function(e) {
+		this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
+		this.titleBar.style.color           = this.accordion.options.hoverTextColor;
+   },
+
+   unhover: function(e) {
+      if ( this.expanded ) {
+         this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
+         this.titleBar.style.color           = this.accordion.options.expandedTextColor;
+      }
+      else {
+         this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
+         this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
+      }
+   },
+
+   _attachBehaviors: function() {
+      this.content.style.border = "1px solid " + this.accordion.options.borderColor;
+      this.content.style.borderTopWidth    = "0px";
+      this.content.style.borderBottomWidth = "0px";
+      this.content.style.margin            = "0px";
+
+      this.titleBar.onclick     = this.titleBarClicked.bindAsEventListener(this);
+      this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
+      this.titleBar.onmouseout  = this.unhover.bindAsEventListener(this);
+   }
+
+};
+
+
+//-------------------- ricoAjaxEngine.js
+
+Rico.AjaxEngine = Class.create();
+
+Rico.AjaxEngine.prototype = {
+
+   initialize: function() {
+      this.ajaxElements = new Array();
+      this.ajaxObjects  = new Array();
+      this.requestURLS  = new Array();
+   },
+
+   registerAjaxElement: function( anId, anElement ) {
+      if ( arguments.length == 1 )
+         anElement = $(anId);
+      this.ajaxElements[anId] = anElement;
+   },
+
+   registerAjaxObject: function( anId, anObject ) {
+      this.ajaxObjects[anId] = anObject;
+   },
+
+   registerRequest: function (requestLogicalName, requestURL) {
+      this.requestURLS[requestLogicalName] = requestURL;
+   },
+
+   sendRequest: function(requestName) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      var queryString = "";
+      
+      if ( arguments.length > 1 ) {
+      	 if(typeof(arguments[1]) == "object" && arguments[1].length != undefined) {
+	      	 queryString = this._createQueryString(arguments[1], 0);
+      	 }
+      	 else {
+	         queryString = this._createQueryString(arguments, 1);
+	     }         
+       }
+             
+      new Ajax.Request(requestURL, this._requestOptions(queryString));
+   },
+
+   sendRequestWithData: function(requestName, xmlDocument) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      var queryString = "";
+      if ( arguments.length > 2 ) {
+      	 if(typeof(arguments[2]) == "object" && arguments[2].length != undefined) {
+	      	 queryString = this._createQueryString(arguments[2], 0);
+      	 }
+      	 else {
+	         queryString = this._createQueryString(arguments, 2);
+	     }         
+       }             
+
+      new Ajax.Request(requestURL + "?" + queryString, this._requestOptions(null,xmlDocument));
+   },
+
+   sendRequestAndUpdate: function(requestName,container,options) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      var queryString = "";
+      if ( arguments.length > 3 ) {
+      	 if(typeof(arguments[3]) == "object" && arguments[3].length != undefined) {
+	      	 queryString = this._createQueryString(arguments[3], 0);
+      	 }
+      	 else {
+	         queryString = this._createQueryString(arguments, 3);
+	     }         
+       }  
+             
+      var updaterOptions = this._requestOptions(queryString);
+      updaterOptions.onComplete = null;
+      updaterOptions.extend(options);
+
+      new Ajax.Updater(container, requestURL, updaterOptions);
+   },
+
+   sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
+      var requestURL = this.requestURLS[requestName];
+      if ( requestURL == null )
+         return;
+
+      var queryString = "";
+      if ( arguments.length > 4 ) {
+      	 if(typeof(arguments[4]) == "object" && arguments[4].length != undefined) {
+	      	 queryString = this._createQueryString(arguments[4], 0);
+      	 }
+      	 else {
+	         queryString = this._createQueryString(arguments, 4);
+	     }         
+       }
+
+
+      var updaterOptions = this._requestOptions(queryString,xmlDocument);
+      updaterOptions.onComplete = null;
+      updaterOptions.extend(options);
+
+      new Ajax.Updater(container, requestURL + "?" + queryString, updaterOptions);
+   },
+
+   // Private -- not part of intended engine API --------------------------------------------------------------------
+
+   _requestOptions: function(queryString,xmlDoc) {
+      var self = this;
+
+      var requestHeaders = ['X-Rico-Version', Rico.Version ];
+      var sendMethod = "post"
+      if ( arguments[1] )
+         requestHeaders.push( 'Content-type', 'text/xml' );
+      else
+         sendMethod = "get";
+
+      return { requestHeaders: requestHeaders,
+               parameters:     queryString,
+               postBody:       arguments[1] ? xmlDoc : null,
+               method:         sendMethod,
+               onComplete:     self._onRequestComplete.bind(self) };
+   },
+
+   _createQueryString: function( theArgs, offset ) {
+   	  var self = this;
+      var queryString = ""
+      for ( var i = offset ; i < theArgs.length ; i++ ) {
+          if ( i != offset )
+            queryString += "&";
+
+          var anArg = theArgs[i];
+                  
+          if ( anArg.name != undefined && anArg.value != undefined ) {
+            queryString += anArg.name +  "=" + escape(anArg.value);
+          }
+          else {
+             var ePos  = anArg.indexOf('=');
+             var argName  = anArg.substring( 0, ePos );
+             var argValue = anArg.substring( ePos + 1 );
+             queryString += argName + "=" + escape(argValue);
+          }
+      }
+
+      return queryString;
+   },
+   _onRequestComplete : function(request) {
+
+      //!!TODO: error handling infrastructure?? 
+      if (request.status != 200)
+        return;
+
+      var response = request.responseXML.getElementsByTagName("ajax-response");
+      if (response == null || response.length != 1)
+         return;
+      this._processAjaxResponse( response[0].childNodes );
+   },
+
+   _processAjaxResponse: function( xmlResponseElements ) {
+      for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
+         var responseElement = xmlResponseElements[i];
+
+         // only process nodes of type element.....
+         if ( responseElement.nodeType != 1 )
+            continue;
+
+         var responseType = responseElement.getAttribute("type");
+         var responseId   = responseElement.getAttribute("id");
+
+         if ( responseType == "object" )
+            this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
+         else if ( responseType == "element" )
+            this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
+         else
+            alert('unrecognized AjaxResponse type : ' + responseType );
+      }
+   },
+
+   _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
+      ajaxObject.ajaxUpdate( responseElement );
+   },
+
+   _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
+      ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
+   }
+
+}
+
+var ajaxEngine = new Rico.AjaxEngine();
+
+
+//-------------------- ricoColor.js
+Rico.Color = Class.create();
+
+Rico.Color.prototype = {
+
+   initialize: function(red, green, blue) {
+      this.rgb = { r: red, g : green, b : blue };
+   },
+
+   setRed: function(r) {
+      this.rgb.r = r;
+   },
+
+   setGreen: function(g) {
+      this.rgb.g = g;
+   },
+
+   setBlue: function(b) {
+      this.rgb.b = b;
+   },
+
+   setHue: function(h) {
+
+      // get an HSB model, and set the new hue...
+      var hsb = this.asHSB();
+      hsb.h = h;
+
+      // convert back to RGB...
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+   },
+
+   setSaturation: function(s) {
+      // get an HSB model, and set the new hue...
+      var hsb = this.asHSB();
+      hsb.s = s;
+
+      // convert back to RGB and set values...
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
+   },
+
+   setBrightness: function(b) {
+      // get an HSB model, and set the new hue...
+      var hsb = this.asHSB();
+      hsb.b = b;
+
+      // convert back to RGB and set values...
+      this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
+   },
+
+   darken: function(percent) {
+      var hsb  = this.asHSB();
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
+   },
+
+   brighten: function(percent) {
+      var hsb  = this.asHSB();
+      this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
+   },
+
+   blend: function(other) {
+      this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
+      this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
+      this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
+   },
+
+   isBright: function() {
+      var hsb = this.asHSB();
+      return this.asHSB().b > 0.5;
+   },
+
+   isDark: function() {
+      return ! this.isBright();
+   },
+
+   asRGB: function() {
+      return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
+   },
+
+   asHex: function() {
+      return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
+   },
+
+   asHSB: function() {
+      return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
+   },
+
+   toString: function() {
+      return this.asHex();
+   }
+
+};
+
+Rico.Color.createFromHex = function(hexCode) {
+
+   if ( hexCode.indexOf('#') == 0 )
+      hexCode = hexCode.substring(1);
+   var red   = hexCode.substring(0,2);
+   var green = hexCode.substring(2,4);
+   var blue  = hexCode.substring(4,6);
+   return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
+}
+
+/**
+ * Factory method for creating a color from the background of
+ * an HTML element.
+ */
+Rico.Color.createColorFromBackground = function(elem) {
+
+   var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
+
+   if ( actualColor == "transparent" && elem.parent )
+      return Rico.Color.createColorFromBackground(elem.parent);
+
+   if ( actualColor == null )
+      return new Rico.Color(255,255,255);
+
+   if ( actualColor.indexOf("rgb(") == 0 ) {
+      var colors = actualColor.substring(4, actualColor.length - 1 );
+      var colorArray = colors.split(",");
+      return new Rico.Color( parseInt( colorArray[0] ),
+                            parseInt( colorArray[1] ),
+                            parseInt( colorArray[2] )  );
+
+   }
+   else if ( actualColor.indexOf("#") == 0 ) {
+      var redPart   = parseInt(actualColor.substring(1,3), 16);
+      var greenPart = parseInt(actualColor.substring(3,5), 16);
+      var bluePart  = parseInt(actualColor.substring(5), 16);
+      return new Rico.Color( redPart, greenPart, bluePart );
+   }
+   else
+      return new Rico.Color(255,255,255);
+}
+
+Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
+
+   var red   = 0;
+	var green = 0;
+	var blue  = 0;
+
+   if (saturation == 0) {
+      red = parseInt(brightness * 255.0 + 0.5);
+	   green = red;
+	   blue = red;
+	}
+	else {
+      var h = (hue - Math.floor(hue)) * 6.0;
+      var f = h - Math.floor(h);
+      var p = brightness * (1.0 - saturation);
+      var q = brightness * (1.0 - saturation * f);
+      var t = brightness * (1.0 - (saturation * (1.0 - f)));
+
+      switch (parseInt(h)) {
+         case 0:
+            red   = (brightness * 255.0 + 0.5);
+            green = (t * 255.0 + 0.5);
+            blue  = (p * 255.0 + 0.5);
+            break;
+         case 1:
+            red   = (q * 255.0 + 0.5);
+            green = (brightness * 255.0 + 0.5);
+            blue  = (p * 255.0 + 0.5);
+            break;
+         case 2:
+            red   = (p * 255.0 + 0.5);
+            green = (brightness * 255.0 + 0.5);
+            blue  = (t * 255.0 + 0.5);
+            break;
+         case 3:
+            red   = (p * 255.0 + 0.5);
+            green = (q * 255.0 + 0.5);
+            blue  = (brightness * 255.0 + 0.5);
+            break;
+         case 4:
+            red   = (t * 255.0 + 0.5);
+            green = (p * 255.0 + 0.5);
+            blue  = (brightness * 255.0 + 0.5);
+            break;
+          case 5:
+            red   = (brightness * 255.0 + 0.5);
+            green = (p * 255.0 + 0.5);
+            blue  = (q * 255.0 + 0.5);
+            break;
+	    }
+	}
+
+   return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
+}
+
+Rico.Color.RGBtoHSB = function(r, g, b) {
+
+   var hue;
+   var saturaton;
+   var brightness;
+
+   var cmax = (r > g) ? r : g;
+   if (b > cmax)
+      cmax = b;
+
+   var cmin = (r < g) ? r : g;
+   if (b < cmin)
+      cmin = b;
+
+   brightness = cmax / 255.0;
+   if (cmax != 0)
+      saturation = (cmax - cmin)/cmax;
+   else
+      saturation = 0;
+
+   if (saturation == 0)
+      hue = 0;
+   else {
+      var redc   = (cmax - r)/(cmax - cmin);
+    	var greenc = (cmax - g)/(cmax - cmin);
+    	var bluec  = (cmax - b)/(cmax - cmin);
+
+    	if (r == cmax)
+    	   hue = bluec - greenc;
+    	else if (g == cmax)
+    	   hue = 2.0 + redc - bluec;
+      else
+    	   hue = 4.0 + greenc - redc;
+
+    	hue = hue / 6.0;
+    	if (hue < 0)
+    	   hue = hue + 1.0;
+   }
+
+   return { h : hue, s : saturation, b : brightness };
+}
+
+
+//-------------------- ricoCorner.js
+
+Rico.Corner = {
+
+   round: function(e, options) {
+      var e = $(e);
+      this._setOptions(options);
+
+      var color = this.options.color;
+      if ( this.options.color == "fromElement" )
+         color = this._background(e);
+
+      var bgColor = this.options.bgColor;
+      if ( this.options.bgColor == "fromParent" )
+         bgColor = this._background(e.offsetParent);
+
+      this._roundCornersImpl(e, color, bgColor);
+   },
+
+   _roundCornersImpl: function(e, color, bgColor) {
+      if(this.options.border)
+         this._renderBorder(e,bgColor);
+      if(this._isTopRounded())
+         this._roundTopCorners(e,color,bgColor);
+      if(this._isBottomRounded())
+         this._roundBottomCorners(e,color,bgColor);
+   },
+
+   _renderBorder: function(el,bgColor) {
+      var borderValue = "1px solid " + this._borderColor(bgColor);
+      var borderL = "border-left: "  + borderValue;
+      var borderR = "border-right: " + borderValue;
+      var style   = "style='" + borderL + ";" + borderR +  "'";
+      el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
+   },
+
+   _roundTopCorners: function(el, color, bgColor) {
+      var corner = this._createCorner(bgColor);
+      for(var i=0 ; i < this.options.numSlices ; i++ )
+         corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
+      el.style.paddingTop = 0;
+      el.insertBefore(corner,el.firstChild);
+   },
+
+   _roundBottomCorners: function(el, color, bgColor) {
+      var corner = this._createCorner(bgColor);
+      for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
+         corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
+      el.style.paddingBottom = 0;
+      el.appendChild(corner);
+   },
+
+   _createCorner: function(bgColor) {
+      var corner = document.createElement("div");
+      corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
+      return corner;
+   },
+
+   _createCornerSlice: function(color,bgColor, n, position) {
+      var slice = document.createElement("span");
+
+      var inStyle = slice.style;
+      inStyle.backgroundColor = color;
+      inStyle.display  = "block";
+      inStyle.height   = "1px";
+      inStyle.overflow = "hidden";
+      inStyle.fontSize = "1px";
+
+      var borderColor = this._borderColor(color,bgColor);
+      if ( this.options.border && n == 0 ) {
+         inStyle.borderTopStyle    = "solid";
+         inStyle.borderTopWidth    = "1px";
+         inStyle.borderLeftWidth   = "0px";
+         inStyle.borderRightWidth  = "0px";
+         inStyle.borderBottomWidth = "0px";
+         inStyle.height            = "0px"; // assumes css compliant box model
+         inStyle.borderColor       = borderColor;
+      }
+      else if(borderColor) {
+         inStyle.borderColor = borderColor;
+         inStyle.borderStyle = "solid";
+         inStyle.borderWidth = "0px 1px";
+      }
+
+      if ( !this.options.compact && (n == (this.options.numSlices-1)) )
+         inStyle.height = "2px";
+
+      this._setMargin(slice, n, position);
+      this._setBorder(slice, n, position);
+
+      return slice;
+   },
+
+   _setOptions: function(options) {
+      this.options = {
+         corners : "all",
+         color   : "fromElement",
+         bgColor : "fromParent",
+         blend   : true,
+         border  : false,
+         compact : false
+      }.extend(options || {});
+
+      this.options.numSlices = this.options.compact ? 2 : 4;
+      if ( this._isTransparent() )
+         this.options.blend = false;
+   },
+
+   _whichSideTop: function() {
+      if ( this._hasString(this.options.corners, "all", "top") )
+         return "";
+
+      if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
+         return "";
+
+      if (this.options.corners.indexOf("tl") >= 0)
+         return "left";
+      else if (this.options.corners.indexOf("tr") >= 0)
+          return "right";
+      return "";
+   },
+
+   _whichSideBottom: function() {
+      if ( this._hasString(this.options.corners, "all", "bottom") )
+         return "";
+
+      if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
+         return "";
+
+      if(this.options.corners.indexOf("bl") >=0)
+         return "left";
+      else if(this.options.corners.indexOf("br")>=0)
+         return "right";
+      return "";
+   },
+
+   _borderColor : function(color,bgColor) {
+      if ( color == "transparent" )
+         return bgColor;
+      else if ( this.options.border )
+         return this.options.border;
+      else if ( this.options.blend )
+         return this._blend( bgColor, color );
+      else
+         return "";
+   },
+
+
+   _setMargin: function(el, n, corners) {
+      var marginSize = this._marginSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+
+      if ( whichSide == "left" ) {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
+      }
+      else {
+         el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
+      }
+   },
+
+   _setBorder: function(el,n,corners) {
+      var borderSize = this._borderSize(n);
+      var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
+
+      if ( whichSide == "left" ) {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
+      }
+      else if ( whichSide == "right" ) {
+         el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
+      }
+      else {
+         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
+      }
+   },
+
+   _marginSize: function(n) {
+      if ( this._isTransparent() )
+         return 0;
+
+      var marginSizes          = [ 5, 3, 2, 1 ];
+      var blendedMarginSizes   = [ 3, 2, 1, 0 ];
+      var compactMarginSizes   = [ 2, 1 ];
+      var smBlendedMarginSizes = [ 1, 0 ];
+
+      if ( this.options.compact && this.options.blend )
+         return smBlendedMarginSizes[n];
+      else if ( this.options.compact )
+         return compactMarginSizes[n];
+      else if ( this.options.blend )
+         return blendedMarginSizes[n];
+      else
+         return marginSizes[n];
+   },
+
+   _borderSize: function(n) {
+      var transparentBorderSizes = [ 5, 3, 2, 1 ];
+      var blendedBorderSizes     = [ 2, 1, 1, 1 ];
+      var compactBorderSizes     = [ 1, 0 ];
+      var actualBorderSizes      = [ 0, 2, 0, 0 ];
+
+      if ( this.options.compact && (this.options.blend || this._isTransparent()) )
+         return 1;
+      else if ( this.options.compact )
+         return compactBorderSizes[n];
+      else if ( this.options.blend )
+         return blendedBorderSizes[n];
+      else if ( this.options.border )
+         return actualBorderSizes[n];
+      else if ( this._isTransparent() )
+         return transparentBorderSizes[n];
+      return 0;
+   },
+
+   _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
+   _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
+   _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
+   _isTransparent: function() { return this.options.color == "transparent"; },
+   _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
+   _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
+   _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
+}
+
+
+//-------------------- ricoDragAndDrop.js
+Rico.DragAndDrop = Class.create();
+
+Rico.DragAndDrop.prototype = {
+
+   initialize: function() {
+      this.dropZones                = new Array();
+      this.draggables               = new Array();
+      this.currentDragObjects       = new Array();
+      this.dragElement              = null;
+      this.lastSelectedDraggable    = null;
+      this.currentDragObjectVisible = false;
+      this.interestedInMotionEvents = false;
+   },
+
+   registerDropZone: function(aDropZone) {
+      this.dropZones[ this.dropZones.length ] = aDropZone;
+   },
+
+   deregisterDropZone: function(aDropZone) {
+      var newDropZones = new Array();
+      var j = 0;
+      for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
+         if ( this.dropZones[i] != aDropZone )
+            newDropZones[j++] = this.dropZones[i];
+      }
+
+      this.dropZones = newDropZones;
+   },
+
+   clearDropZones: function() {
+      this.dropZones = new Array();
+   },
+
+   registerDraggable: function( aDraggable ) {
+      this.draggables[ this.draggables.length ] = aDraggable;
+      this._addMouseDownHandler( aDraggable );
+   },
+
+   clearSelection: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].deselect();
+      this.currentDragObjects = new Array();
+      this.lastSelectedDraggable = null;
+   },
+
+   hasSelection: function() {
+      return this.currentDragObjects.length > 0;
+   },
+
+   setStartDragFromElement: function( e, mouseDownElement ) {
+      this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
+      this.startx = e.screenX - this.origPos.x
+      this.starty = e.screenY - this.origPos.y
+      //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
+      //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
+      //this.adjustedForDraggableSize = false;
+
+      this.interestedInMotionEvents = this.hasSelection();
+      this._terminateEvent(e);
+   },
+
+   updateSelection: function( draggable, extendSelection ) {
+      if ( ! extendSelection )
+         this.clearSelection();
+
+      if ( draggable.isSelected() ) {
+         this.currentDragObjects.removeItem(draggable);
+         draggable.deselect();
+         if ( draggable == this.lastSelectedDraggable )
+            this.lastSelectedDraggable = null;
+      }
+      else {
+         this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
+         draggable.select();
+         this.lastSelectedDraggable = draggable;
+      }
+   },
+
+   _mouseDownHandler: function(e) {
+      if ( arguments.length == 0 )
+         e = event;
+
+      // if not button 1 ignore it...
+      var nsEvent = e.which != undefined;
+      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
+         return;
+
+      var eventTarget      = e.target ? e.target : e.srcElement;
+      var draggableObject  = eventTarget.draggable;
+
+      var candidate = eventTarget;
+      while (draggableObject == null && candidate.parentNode) {
+         candidate = candidate.parentNode;
+         draggableObject = candidate.draggable;
+      }
+   
+      if ( draggableObject == null )
+         return;
+
+      this.updateSelection( draggableObject, e.ctrlKey );
+
+      // clear the drop zones postion cache...
+      if ( this.hasSelection() )
+         for ( var i = 0 ; i < this.dropZones.length ; i++ )
+            this.dropZones[i].clearPositionCache();
+
+      this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
+   },
+
+
+   _mouseMoveHandler: function(e) {
+      var nsEvent = e.which != undefined;
+      if ( !this.interestedInMotionEvents ) {
+         this._terminateEvent(e);
+         return;
+      }
+
+      if ( ! this.hasSelection() )
+         return;
+
+      if ( ! this.currentDragObjectVisible )
+         this._startDrag(e);
+
+      if ( !this.activatedDropZones )
+         this._activateRegisteredDropZones();
+
+      //if ( !this.adjustedForDraggableSize )
+      //   this._adjustForDraggableSize(e);
+
+      this._updateDraggableLocation(e);
+      this._updateDropZonesHover(e);
+
+      this._terminateEvent(e);
+   },
+
+   _makeDraggableObjectVisible: function(e)
+   {
+      if ( !this.hasSelection() )
+         return;
+
+      var dragElement;
+      if ( this.currentDragObjects.length > 1 )
+         dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
+      else
+         dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
+
+      // go ahead and absolute position it...
+      if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
+         dragElement.style.position = "absolute";
+
+      // need to parent him into the document...
+      if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
+         document.body.appendChild(dragElement);
+
+      this.dragElement = dragElement;
+      this._updateDraggableLocation(e);
+
+      this.currentDragObjectVisible = true;
+   },
+
+   /**
+   _adjustForDraggableSize: function(e) {
+      var dragElementWidth  = this.dragElement.offsetWidth;
+      var dragElementHeight = this.dragElement.offsetHeight;
+      if ( this.startComponentX > dragElementWidth )
+         this.startx -= this.startComponentX - dragElementWidth + 2;
+      if ( e.offsetY ) {
+         if ( this.startComponentY > dragElementHeight )
+            this.starty -= this.startComponentY - dragElementHeight + 2;
+      }
+      this.adjustedForDraggableSize = true;
+   },
+   **/
+
+   _updateDraggableLocation: function(e) {
+      var dragObjectStyle = this.dragElement.style;
+      dragObjectStyle.left = (e.screenX - this.startx) + "px"
+      dragObjectStyle.top  = (e.screenY - this.starty) + "px";
+   },
+
+   _updateDropZonesHover: function(e) {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
+            this.dropZones[i].hideHover();
+      }
+
+      for ( var i = 0 ; i < n ; i++ ) {
+         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
+            if ( this.dropZones[i].canAccept(this.currentDragObjects) )
+               this.dropZones[i].showHover();
+         }
+      }
+   },
+
+   _startDrag: function(e) {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].startDrag();
+
+      this._makeDraggableObjectVisible(e);
+   },
+
+   _mouseUpHandler: function(e) {
+      if ( ! this.hasSelection() )
+         return;
+
+      var nsEvent = e.which != undefined;
+      if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
+         return;
+
+      this.interestedInMotionEvents = false;
+
+      if ( this.dragElement == null ) {
+         this._terminateEvent(e);
+         return;
+      }
+
+      if ( this._placeDraggableInDropZone(e) )
+         this._completeDropOperation(e);
+      else {
+         this._terminateEvent(e);
+         new Effect.Position( this.dragElement,
+                              this.origPos.x,
+                              this.origPos.y,
+                              200,
+                              20,
+                              { complete : this._doCancelDragProcessing.bind(this) } );
+      }
+   },
+
+   _completeDropOperation: function(e) {
+      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
+         if ( this.dragElement.parentNode != null )
+            this.dragElement.parentNode.removeChild(this.dragElement);
+      }
+
+      this._deactivateRegisteredDropZones();
+      this._endDrag();
+      this.clearSelection();
+      this.dragElement = null;
+      this.currentDragObjectVisible = false;
+      this._terminateEvent(e);
+   },
+
+   _doCancelDragProcessing: function() {
+      this._cancelDrag();
+
+      if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
+         if ( this.dragElement.parentNode != null ) {
+            this.dragElement.parentNode.removeChild(this.dragElement);
+         }
+      }
+
+      this._deactivateRegisteredDropZones();
+      this.dragElement = null;
+      this.currentDragObjectVisible = false;
+   },
+
+   _placeDraggableInDropZone: function(e) {
+      var foundDropZone = false;
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
+            if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
+               this.dropZones[i].hideHover();
+               this.dropZones[i].accept(this.currentDragObjects);
+               foundDropZone = true;
+               break;
+            }
+         }
+      }
+
+      return foundDropZone;
+   },
+
+   _cancelDrag: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].cancelDrag();
+   },
+
+   _endDrag: function() {
+      for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
+         this.currentDragObjects[i].endDrag();
+   },
+
+   _mousePointInDropZone: function( e, dropZone ) {
+
+      var absoluteRect = dropZone.getAbsoluteRect();
+
+      return e.clientX  > absoluteRect.left  &&
+             e.clientX  < absoluteRect.right &&
+             e.clientY  > absoluteRect.top   &&
+             e.clientY  < absoluteRect.bottom;
+   },
+
+   _addMouseDownHandler: function( aDraggable )
+   {
+      var htmlElement = aDraggable.getMouseDownHTMLElement();
+      if ( htmlElement != null ) {
+         htmlElement.draggable = aDraggable;
+         this._addMouseDownEvent( htmlElement );
+      }
+   },
+
+   _activateRegisteredDropZones: function() {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ ) {
+         var dropZone = this.dropZones[i];
+         if ( dropZone.canAccept(this.currentDragObjects) )
+            dropZone.activate();
+      }
+
+      this.activatedDropZones = true;
+   },
+
+   _deactivateRegisteredDropZones: function() {
+      var n = this.dropZones.length;
+      for ( var i = 0 ; i < n ; i++ )
+         this.dropZones[i].deactivate();
+      this.activatedDropZones = false;
+   },
+
+   _addMouseDownEvent: function( htmlElement ) {
+      if ( typeof document.implementation != "undefined" &&
+         document.implementation.hasFeature("HTML",   "1.0") &&
+         document.implementation.hasFeature("Events", "2.0") &&
+         document.implementation.hasFeature("CSS",    "2.0") ) {
+         htmlElement.addEventListener("mousedown", this._mouseDownHandler.bindAsEventListener(this), false);
+      }
+      else {
+         htmlElement.attachEvent( "onmousedown", this._mouseDownHandler.bindAsEventListener(this) );
+      }
+   },
+
+   _terminateEvent: function(e) {
+      if ( e.stopPropagation != undefined )
+         e.stopPropagation();
+      else if ( e.cancelBubble != undefined )
+         e.cancelBubble = true;
+
+      if ( e.preventDefault != undefined )
+         e.preventDefault();
+      else
+         e.returnValue = false;
+   },
+
+   initializeEventHandlers: function() {
+      if ( typeof document.implementation != "undefined" &&
+         document.implementation.hasFeature("HTML",   "1.0") &&
+         document.implementation.hasFeature("Events", "2.0") &&
+         document.implementation.hasFeature("CSS",    "2.0") ) {
+         document.addEventListener("mouseup",   this._mouseUpHandler.bindAsEventListener(this),  false);
+         document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
+      }
+      else {
+         document.attachEvent( "onmouseup",   this._mouseUpHandler.bindAsEventListener(this) );
+         document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
+      }
+   }
+}
+
+//var dndMgr = new Rico.DragAndDrop();
+//dndMgr.initializeEventHandlers();
+
+
+//-------------------- ricoDraggable.js
+Rico.Draggable = Class.create();
+
+Rico.Draggable.prototype = {
+
+   initialize: function( type, htmlElement ) {
+      this.type          = type;
+      this.htmlElement   = $(htmlElement);
+      this.selected      = false;
+   },
+
+   /**
+    *   Returns the HTML element that should have a mouse down event
+    *   added to it in order to initiate a drag operation
+    *
+    **/
+   getMouseDownHTMLElement: function() {
+      return this.htmlElement;
+   },
+
+   select: function() {
+      this.selected = true;
+
+      if ( this.showingSelected )
+         return;
+
+      var htmlElement = this.getMouseDownHTMLElement();
+
+      var color = Rico.Color.createColorFromBackground(htmlElement);
+      color.isBright() ? color.darken(0.033) : color.brighten(0.033);
+
+      this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
+      htmlElement.style.backgroundColor = color.asHex();
+      this.showingSelected = true;
+   },
+
+   deselect: function() {
+      this.selected = false;
+      if ( !this.showingSelected )
+         return;
+
+      var htmlElement = this.getMouseDownHTMLElement();
+
+      htmlElement.style.backgroundColor = this.saveBackground;
+      this.showingSelected = false;
+   },
+
+   isSelected: function() {
+      return this.selected;
+   },
+
+   startDrag: function() {
+   },
+
+   cancelDrag: function() {
+   },
+
+   endDrag: function() {
+   },
+
+   getSingleObjectDragGUI: function() {
+      return this.htmlElement;
+   },
+
+   getMultiObjectDragGUI: function( draggables ) {
+      return this.htmlElement;
+   },
+
+   getDroppedGUI: function() {
+      return this.htmlElement;
+   },
+
+   toString: function() {
+      return this.type + ":" + this.htmlElement + ":";
+   }
+
+}
+
+
+//-------------------- ricoDropzone.js
+Rico.Dropzone = Class.create();
+
+Rico.Dropzone.prototype = {
+
+   initialize: function( htmlElement ) {
+      this.htmlElement  = $(htmlElement);
+      this.absoluteRect = null;
+   },
+
+   getHTMLElement: function() {
+      return this.htmlElement;
+   },
+
+   clearPositionCache: function() {
+      this.absoluteRect = null;
+   },
+
+   getAbsoluteRect: function() {
+      if ( this.absoluteRect == null ) {
+         var htmlElement = this.getHTMLElement();
+         var pos = RicoUtil.toViewportPosition(htmlElement);
+
+         this.absoluteRect = {
+            top:    pos.y,
+            left:   pos.x,
+            bottom: pos.y + htmlElement.offsetHeight,
+            right:  pos.x + htmlElement.offsetWidth
+         };
+      }
+      return this.absoluteRect;
+   },
+
+   activate: function() {
+      var htmlElement = this.getHTMLElement();
+      if (htmlElement == null  || this.showingActive)
+         return;
+
+      this.showingActive = true;
+      this.saveBackgroundColor = htmlElement.style.backgroundColor;
+
+      var fallbackColor = "#ffea84";
+      var currentColor = Rico.Color.createColorFromBackground(htmlElement);
+      if ( currentColor == null )
+         htmlElement.style.backgroundColor = fallbackColor;
+      else {
+         currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
+         htmlElement.style.backgroundColor = currentColor.asHex();
+      }
+   },
+
+   deactivate: function() {
+      var htmlElement = this.getHTMLElement();
+      if (htmlElement == null || !this.showingActive)
+         return;
+
+      htmlElement.style.backgroundColor = this.saveBackgroundColor;
+      this.showingActive = false;
+      this.saveBackgroundColor = null;
+   },
+
+   showHover: function() {
+      var htmlElement = this.getHTMLElement();
+      if ( htmlElement == null || this.showingHover )
+         return;
+
+      this.saveBorderWidth = htmlElement.style.borderWidth;
+      this.saveBorderStyle = htmlElement.style.borderStyle;
+      this.saveBorderColor = htmlElement.style.borderColor;
+
+      this.showingHover = true;
+      htmlElement.style.borderWidth = "1px";
+      htmlElement.style.borderStyle = "solid";
+      //htmlElement.style.borderColor = "#ff9900";
+      htmlElement.style.borderColor = "#ffff00";
+   },
+
+   hideHover: function() {
+      var htmlElement = this.getHTMLElement();
+      if ( htmlElement == null || !this.showingHover )
+         return;
+
+      htmlElement.style.borderWidth = this.saveBorderWidth;
+      htmlElement.style.borderStyle = this.saveBorderStyle;
+      htmlElement.style.borderColor = this.saveBorderColor;
+      this.showingHover = false;
+   },
+
+   canAccept: function(draggableObjects) {
+      return true;
+   },
+
+   accept: function(draggableObjects) {
+      var htmlElement = this.getHTMLElement();
+      if ( htmlElement == null )
+         return;
+
+      n = draggableObjects.length;
+      for ( var i = 0 ; i < n ; i++ )
+      {
+         var theGUI = draggableObjects[i].getDroppedGUI();
+         if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
+         {
+            theGUI.style.position = "static";
+            theGUI.style.top = "";
+            theGUI.style.top = "";
+         }
+         htmlElement.appendChild(theGUI);
+      }
+   }
+}
+
+
+//-------------------- ricoEffects.js
+
+/**
+  *  Use the Effect namespace for effects.  If using scriptaculous effects
+  *  this will already be defined, otherwise we'll just create an empty
+  *  object for it...
+ **/
+if ( window.Effect == undefined )
+   Effect = {};
+
+Effect.SizeAndPosition = Class.create();
+Effect.SizeAndPosition.prototype = {
+
+   initialize: function(element, x, y, w, h, duration, steps, options) {
+      this.element = $(element);
+      this.x = x;
+      this.y = y;
+      this.w = w;
+      this.h = h;
+      this.duration = duration;
+      this.steps    = steps;
+      this.options  = arguments[7] || {};
+
+      this.sizeAndPosition();
+   },
+
+   sizeAndPosition: function() {
+      if (this.isFinished()) {
+         if(this.options.complete) this.options.complete(this);
+         return;
+      }
+
+      if (this.timer)
+         clearTimeout(this.timer);
+
+      var stepDuration = Math.round(this.duration/this.steps) ;
+
+      // Get original values: x,y = top left corner;  w,h = width height
+      var currentX = this.element.offsetLeft;
+      var currentY = this.element.offsetTop;
+      var currentW = this.element.offsetWidth;
+      var currentH = this.element.offsetHeight;
+
+      // If values not set, or zero, we do not modify them, and take original as final as well
+      this.x = (this.x) ? this.x : currentX;
+      this.y = (this.y) ? this.y : currentY;
+      this.w = (this.w) ? this.w : currentW;
+      this.h = (this.h) ? this.h : currentH;
+
+      // how much do we need to modify our values for each step?
+      var difX = this.steps >  0 ? (this.x - currentX)/this.steps : 0;
+      var difY = this.steps >  0 ? (this.y - currentY)/this.steps : 0;
+      var difW = this.steps >  0 ? (this.w - currentW)/this.steps : 0;
+      var difH = this.steps >  0 ? (this.h - currentH)/this.steps : 0;
+
+      this.moveBy(difX, difY);
+      this.resizeBy(difW, difH);
+
+      this.duration -= stepDuration;
+      this.steps--;
+
+      this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
+   },
+
+   isFinished: function() {
+      return this.steps <= 0;
+   },
+
+   moveBy: function( difX, difY ) {
+      var currentLeft = this.element.offsetLeft;
+      var currentTop  = this.element.offsetTop;
+      var intDifX     = parseInt(difX);
+      var intDifY     = parseInt(difY);
+
+      var style = this.element.style;
+      if ( intDifX != 0 )
+         style.left = (currentLeft + intDifX) + "px";
+      if ( intDifY != 0 )
+         style.top  = (currentTop + intDifY) + "px";
+   },
+
+   resizeBy: function( difW, difH ) {
+      var currentWidth  = this.element.offsetWidth;
+      var currentHeight = this.element.offsetHeight;
+      var intDifW       = parseInt(difW);
+      var intDifH       = parseInt(difH);
+
+      var style = this.element.style;
+      if ( intDifW != 0 )
+         style.width   = (currentWidth  + intDifW) + "px";
+      if ( intDifH != 0 )
+         style.height  = (currentHeight + intDifH) + "px";
+   }
+}
+
+Effect.Size = Class.create();
+Effect.Size.prototype = {
+
+   initialize: function(element, w, h, duration, steps, options) {
+      new Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
+  }
+}
+
+Effect.Position = Class.create();
+Effect.Position.prototype = {
+
+   initialize: function(element, x, y, duration, steps, options) {
+      new Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
+  }
+}
+
+Effect.Round = Class.create();
+Effect.Round.prototype = {
+
+   initialize: function(tagName, className, options) {
+      var elements = document.getElementsByTagAndClassName(tagName,className);
+      for ( var i = 0 ; i < elements.length ; i++ )
+         Rico.Corner.round( elements[i], options );
+   }
+};
+
+Effect.FadeTo = Class.create();
+Effect.FadeTo.prototype = {
+
+   initialize: function( element, opacity, duration, steps, options) {
+      this.element  = $(element);
+      this.opacity  = opacity;
+      this.duration = duration;
+      this.steps    = steps;
+      this.options  = arguments[4] || {};
+      this.fadeTo();
+   },
+
+   fadeTo: function() {
+      if (this.isFinished()) {
+         if(this.options.complete) this.options.complete(this);
+         return;
+      }
+
+      if (this.timer)
+         clearTimeout(this.timer);
+
+      var stepDuration = Math.round(this.duration/this.steps) ;
+      var currentOpacity = this.getElementOpacity();
+      var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
+
+      this.changeOpacityBy(delta);
+      this.duration -= stepDuration;
+      this.steps--;
+
+      this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
+   },
+
+   changeOpacityBy: function(v) {
+      var currentOpacity = this.getElementOpacity();
+      var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
+      this.element.ricoOpacity = newOpacity;
+
+      this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
+      this.element.style.opacity = newOpacity; /*//*/;
+   },
+
+   isFinished: function() {
+      return this.steps <= 0;
+   },
+
+   getElementOpacity: function() {
+      if ( this.element.ricoOpacity == undefined ) {
+         var opacity;
+         if ( this.element.currentStyle ) {
+            opacity = this.element.currentStyle.opacity;
+         }
+         else if ( document.defaultView.getComputedStyle != undefined ) {
+            var computedStyle = document.defaultView.getComputedStyle;
+            opacity = computedStyle(this.element, null).getPropertyValue('opacity');
+         }
+
+         this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
+      }
+
+      return parseFloat(this.element.ricoOpacity);
+   }
+}
+
+Effect.AccordionSize = Class.create();
+
+Effect.AccordionSize.prototype = {
+
+   initialize: function(e1, e2, start, end, duration, steps, options) {
+      this.e1       = $(e1);
+      this.e2       = $(e2);
+      this.start    = start;
+      this.end      = end;
+      this.duration = duration;
+      this.steps    = steps;
+      this.options  = arguments[6] || {};
+
+      this.accordionSize();
+   },
+
+   accordionSize: function() {
+
+      if (this.isFinished()) {
+         // just in case there are round errors or such...
+         this.e1.style.height = this.start + "px";
+         this.e2.style.height = this.end + "px";
+
+         if(this.options.complete)
+            this.options.complete(this);
+         return;
+      }
+
+      if (this.timer)
+         clearTimeout(this.timer);
+
+      var stepDuration = Math.round(this.duration/this.steps) ;
+
+      var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
+      this.resizeBy(diff);
+
+      this.duration -= stepDuration;
+      this.steps--;
+
+      this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
+   },
+
+   isFinished: function() {
+      return this.steps <= 0;
+   },
+
+   resizeBy: function(diff) {
+      var h1Height = this.e1.offsetHeight;
+      var h2Height = this.e2.offsetHeight;
+      var intDiff = parseInt(diff);
+      if ( diff != 0 ) {
+         this.e1.style.height = (h1Height - intDiff) + "px";
+         this.e2.style.height = (h2Height + intDiff) + "px";
+      }
+   }
+
+};
+
+
+//-------------------- ricoLiveGrid.js
+
+// Rico.LiveGridMetaData -----------------------------------------------------
+
+Rico.LiveGridMetaData = Class.create();
+
+Rico.LiveGridMetaData.prototype = {
+
+   initialize: function( pageSize, totalRows, columnCount, options ) {
+      this.pageSize  = pageSize;
+      this.totalRows = totalRows;
+      this.setOptions(options);
+      this.scrollArrowHeight = 16;
+      this.columnCount = columnCount;
+   },
+
+   setOptions: function(options) {
+      this.options = {
+         largeBufferSize    : 7.0,   // 7 pages
+         nearLimitFactor    : 0.2    // 20% of buffer
+      }.extend(options || {});
+   },
+
+   getPageSize: function() {
+      return this.pageSize;
+   },
+
+   getTotalRows: function() {
+      return this.totalRows;
+   },
+
+   setTotalRows: function(n) {
+      this.totalRows = n;
+   },
+
+   getLargeBufferSize: function() {
+      return parseInt(this.options.largeBufferSize * this.pageSize);
+   },
+
+   getLimitTolerance: function() {
+      return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
+   }
+};
+
+// Rico.LiveGridScroller -----------------------------------------------------
+
+Rico.LiveGridScroller = Class.create();
+
+Rico.LiveGridScroller.prototype = {
+
+   initialize: function(liveGrid, viewPort) {
+      this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
+      this.liveGrid = liveGrid;
+      this.metaData = liveGrid.metaData;
+      this.createScrollBar();
+      this.scrollTimeout = null;
+      this.lastScrollPos = 0;
+      this.viewPort = viewPort;
+      this.rows = new Array();
+   },
+
+   isUnPlugged: function() {
+      return this.scrollerDiv.onscroll == null;
+   },
+
+   plugin: function() {
+      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
+   },
+
+   unplug: function() {
+      this.scrollerDiv.onscroll = null;
+   },
+
+   sizeIEHeaderHack: function() {
+      if ( !this.isIE ) return;
+      var headerTable = $(this.liveGrid.tableId + "_header");
+      if ( headerTable )
+         headerTable.rows[0].cells[0].style.width =
+            (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
+   },
+
+   createScrollBar: function() {
+      var visibleHeight = this.liveGrid.viewPort.visibleHeight();
+      // create the outer div...
+      this.scrollerDiv  = document.createElement("div");
+      var scrollerStyle = this.scrollerDiv.style;
+      scrollerStyle.borderRight = "1px solid #ababab"; // hard coded color!!!
+      scrollerStyle.position    = "relative";
+      scrollerStyle.left        = this.isIE ? "-6px" : "-3px";
+      scrollerStyle.width       = "19px";
+      scrollerStyle.height      = visibleHeight + "px";
+      scrollerStyle.overflow    = "auto";
+
+      // create the inner div...
+      this.heightDiv = document.createElement("div");
+      this.heightDiv.style.width  = "1px";
+
+      this.heightDiv.style.height = parseInt(visibleHeight *
+                        this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
+      this.scrollerDiv.appendChild(this.heightDiv);
+      this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
+
+     var table = this.liveGrid.table;
+     table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
+   },
+
+   updateSize: function() {
+      var table = this.liveGrid.table;
+      var visibleHeight = this.viewPort.visibleHeight();
+      this.heightDiv.style.height = parseInt(visibleHeight *
+                                  this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
+   },
+
+   rowToPixel: function(rowOffset) {
+      return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
+   },
+   
+   moveScroll: function(rowOffset) {
+      this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
+      if ( this.metaData.options.onscroll )
+         this.metaData.options.onscroll( this.liveGrid, rowOffset );    
+   },
+
+   handleScroll: function() {
+     if ( this.scrollTimeout )
+         clearTimeout( this.scrollTimeout );
+
+      var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
+      this.liveGrid.requestContentRefresh(contentOffset);
+      this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
+      
+      if ( this.metaData.options.onscroll )
+         this.metaData.options.onscroll( this.liveGrid, contentOffset );
+
+      this.scrollTimeout = setTimeout( this.scrollIdle.bind(this), 1200 );
+   },
+
+   scrollIdle: function() {
+      if ( this.metaData.options.onscrollidle )
+         this.metaData.options.onscrollidle();
+   }
+};
+
+// Rico.LiveGridBuffer -----------------------------------------------------
+
+Rico.LiveGridBuffer = Class.create();
+
+Rico.LiveGridBuffer.prototype = {
+
+   initialize: function(metaData, viewPort) {
+      this.startPos = 0;
+      this.size     = 0;
+      this.metaData = metaData;
+      this.rows     = new Array();
+      this.updateInProgress = false;
+      this.viewPort = viewPort;
+      this.maxBufferSize = metaData.getLargeBufferSize() * 2;
+      this.maxFetchSize = metaData.getLargeBufferSize();
+      this.lastOffset = 0;
+   },
+
+   getBlankRow: function() {
+      if (!this.blankRow ) {
+         this.blankRow = new Array();
+         for ( var i=0; i < this.metaData.columnCount ; i++ ) 
+            this.blankRow[i] = "&nbsp;";
+     }
+     return this.blankRow;
+   },
+   
+   loadRows: function(ajaxResponse) {
+      var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
+      this.updateUI = rowsElement.getAttribute("update_ui") == "true"
+      var newRows = new Array()
+      var trs = rowsElement.getElementsByTagName("tr");
+      for ( var i=0 ; i < trs.length; i++ ) {
+         var row = newRows[i] = new Array(); 
+         var cells = trs[i].getElementsByTagName("td");
+         for ( var j=0; j < cells.length ; j++ ) {
+            var cell = cells[j];
+            var convertSpaces = cell.getAttribute("convert_spaces") == "true";
+            var cellContent = RicoUtil.getContentAsString(cell);
+            row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
+            if (!row[j]) 
+               row[j] = '&nbsp;';
+         }
+      }
+      return newRows;
+   },
+      
+   update: function(ajaxResponse, start) {
+     var newRows = this.loadRows(ajaxResponse);
+      if (this.rows.length == 0) { // initial load
+         this.rows = newRows;
+         this.size = this.rows.length;
+         this.startPos = start;
+         return;
+      }
+      if (start > this.startPos) { //appending
+         if (this.startPos + this.rows.length < start) {
+            this.rows =  newRows;
+            this.startPos = start;//
+         } else {
+              this.rows = this.rows.concat( newRows.slice(0, newRows.length));
+            if (this.rows.length > this.maxBufferSize) {
+               var fullSize = this.rows.length;
+               this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
+               this.startPos = this.startPos +  (fullSize - this.rows.length);
+            }
+         }
+      } else { //prepending
+         if (start + newRows.length < this.startPos) {
+            this.rows =  newRows;
+         } else {
+            this.rows = newRows.slice(0, this.startPos).concat(this.rows);
+            if (this.rows.length > this.maxBufferSize) 
+               this.rows = this.rows.slice(0, this.maxBufferSize)
+         }
+         this.startPos =  start;
+      }
+      this.size = this.rows.length;
+   },
+   
+   clear: function() {
+      this.rows = new Array();
+      this.startPos = 0;
+      this.size = 0;
+   },
+
+   isOverlapping: function(start, size) {
+      return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
+   },
+
+   isInRange: function(position) {
+      return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos()); 
+             //&& this.size()  != 0;
+   },
+
+   isNearingTopLimit: function(position) {
+      return position - this.startPos < this.metaData.getLimitTolerance();
+   },
+
+   endPos: function() {
+      return this.startPos + this.rows.length;
+   },
+   
+   isNearingBottomLimit: function(position) {
+      return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
+   },
+
+   isAtTop: function() {
+      return this.startPos == 0;
+   },
+
+   isAtBottom: function() {
+      return this.endPos() == this.metaData.getTotalRows();
+   },
+
+   isNearingLimit: function(position) {
+      return ( !this.isAtTop()    && this.isNearingTopLimit(position)) ||
+             ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
+   },
+
+   getFetchSize: function(offset) {
+      var adjustedOffset = this.getFetchOffset(offset);
+      var adjustedSize = 0;
+      if (adjustedOffset >= this.startPos) { //apending
+         var endFetchOffset = this.maxFetchSize  + adjustedOffset;
+         if (endFetchOffset > this.metaData.totalRows)
+            endFetchOffset = this.metaData.totalRows;
+         adjustedSize = endFetchOffset - adjustedOffset;   
+      } else {//prepending
+         var adjustedSize = this.startPos - adjustedOffset;
+         if (adjustedSize > this.maxFetchSize)
+            adjustedSize = this.maxFetchSize;
+      }
+      return adjustedSize;
+   }, 
+
+   getFetchOffset: function(offset) {
+      var adjustedOffset = offset;
+      if (offset > this.startPos)  //apending
+         adjustedOffset = (offset > this.endPos()) ? offset :  this.endPos(); 
+      else { //prepending
+         if (offset + this.maxFetchSize >= this.startPos) {
+            var adjustedOffset = this.startPos - this.maxFetchSize;
+            if (adjustedOffset < 0)
+               adjustedOffset = 0;
+         }
+      }
+      this.lastOffset = adjustedOffset;
+      return adjustedOffset;
+   },
+
+   getRows: function(start, count) {
+      var begPos = start - this.startPos
+      var endPos = begPos + count
+
+      // er? need more data...
+      if ( endPos > this.size )
+         endPos = this.size
+
+      var results = new Array()
+      var index = 0;
+      for ( var i=begPos ; i < endPos; i++ ) {
+         results[index++] = this.rows[i]
+      }
+      return results
+   },
+
+   convertSpaces: function(s) {
+      return s.split(" ").join("&nbsp;");
+   }
+
+};
+
+
+//Rico.GridViewPort --------------------------------------------------
+Rico.GridViewPort = Class.create();
+
+Rico.GridViewPort.prototype = {
+
+   initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
+      this.lastDisplayedStartPos = 0;
+      this.div = table.parentNode;
+      this.table = table
+      this.rowHeight = rowHeight;
+      this.div.style.height = this.rowHeight * visibleRows;
+      this.div.style.overflow = "hidden";
+      this.buffer = buffer;
+      this.liveGrid = liveGrid;
+      this.visibleRows = visibleRows + 1;
+      this.lastPixelOffset = 0;
+      this.startPos = 0;
+   },
+
+   populateRow: function(htmlRow, row) {
+      for (var j=0; j < row.length; j++) {
+         htmlRow.cells[j].innerHTML = row[j]
+      }
+   },
+   
+   bufferChanged: function() {
+      this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
+   },
+   
+   clearRows: function() {
+      if (!this.isBlank) {
+         for (var i=0; i < this.visibleRows; i++)
+            this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
+         this.isBlank = true;
+      }
+   },
+   
+   clearContents: function() {   
+      this.clearRows();
+      this.scrollTo(0);
+      this.startPos = 0;
+      this.lastStartPos = -1;   
+   },
+   
+   refreshContents: function(startPos) {
+      if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
+         return;
+      }
+      if ((startPos + this.visibleRows < this.buffer.startPos)  
+          || (this.buffer.startPos + this.buffer.size < startPos) 
+          || (this.buffer.size == 0)) {
+         this.clearRows();
+         return;
+      }
+      this.isBlank = false;
+      var viewPrecedesBuffer = this.buffer.startPos > startPos
+      var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos;
+   
+      var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows) 
+                                 ? this.buffer.startPos + this.buffer.size
+                                 : startPos + this.visibleRows;       
+      var rowSize = contentEndPos - contentStartPos;
+      var rows = this.buffer.getRows(contentStartPos, rowSize ); 
+      var blankSize = this.visibleRows - rowSize;
+      var blankOffset = viewPrecedesBuffer ? 0: rowSize;
+      var contentOffset = viewPrecedesBuffer ? blankSize: 0;
+
+      for (var i=0; i < rows.length; i++) {//initialize what we have
+        this.populateRow(this.table.rows[i + contentOffset], rows[i]);
+      }       
+      for (var i=0; i < blankSize; i++) {// blank out the rest 
+        this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
+      }
+      this.isPartialBlank = blankSize > 0;
+      this.lastRowPos = startPos;   
+   },
+
+   scrollTo: function(pixelOffset) {      
+      if (this.lastPixelOffset == pixelOffset)
+         return;
+
+      this.refreshContents(parseInt(pixelOffset / this.rowHeight))
+      this.div.scrollTop = pixelOffset % this.rowHeight        
+      
+      this.lastPixelOffset = pixelOffset;
+   },
+   
+   visibleHeight: function() {
+      return parseInt(this.div.style.height);
+   }
+   
+};
+
+
+Rico.LiveGridRequest = Class.create();
+Rico.LiveGridRequest.prototype = {
+   initialize: function( requestOffset, options ) {
+      this.requestOffset = requestOffset;
+   }
+};
+
+// Rico.LiveGrid -----------------------------------------------------
+
+Rico.LiveGrid = Class.create();
+
+Rico.LiveGrid.prototype = {
+
+   initialize: function( tableId, visibleRows, totalRows, url, options ) {
+      if ( options == null )
+         options = {};
+
+      this.tableId     = tableId; 
+      this.table       = $(tableId);
+      var columnCount  = this.table.rows[0].cells.length
+      this.metaData    = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
+      this.buffer      = new Rico.LiveGridBuffer(this.metaData);
+
+      var rowCount = this.table.rows.length;
+      this.viewPort =  new Rico.GridViewPort(this.table, 
+                                            this.table.offsetHeight/rowCount,
+                                            visibleRows,
+                                            this.buffer, this);
+      this.scroller    = new Rico.LiveGridScroller(this,this.viewPort);
+      
+      this.additionalParms       = options.requestParameters || [];
+      
+      options.sortHandler = this.sortHandler.bind(this);
+
+      if ( $(tableId + '_header') )
+         this.sort = new Rico.LiveGridSort(tableId + '_header', options)
+
+      this.processingRequest = null;
+      this.unprocessedRequest = null;
+
+      this.initAjax(url);
+      if ( options.prefetchBuffer || options.prefetchOffset > 0) {
+         var offset = 0;
+         if (options.offset ) {
+            offset = options.offset;            
+            this.scroller.moveScroll(offset);
+            this.viewPort.scrollTo(this.scroller.rowToPixel(offset));            
+         }
+         if (options.sortCol) {
+             this.sortCol = options.sortCol;
+             this.sortDir = options.sortDir;
+         }
+         this.requestContentRefresh(offset);
+      }
+   },
+
+   resetContents: function() {
+      this.scroller.moveScroll(0);
+      this.buffer.clear();
+      this.viewPort.clearContents();
+   },
+   
+   sortHandler: function(column) {
+      this.sortCol = column.name;
+      this.sortDir = column.currentSort;
+
+      this.resetContents();
+      this.requestContentRefresh(0) 
+   },
+   
+   setRequestParams: function() {
+      this.additionalParms = [];
+      for ( var i=0 ; i < arguments.length ; i++ )
+         this.additionalParms[i] = arguments[i];
+   },
+
+   setTotalRows: function( newTotalRows ) {
+      this.resetContents();
+      this.metaData.setTotalRows(newTotalRows);
+      this.scroller.updateSize();
+   },
+
+   initAjax: function(url) {
+      ajaxEngine.registerRequest( this.tableId + '_request', url );
+      ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
+   },
+
+   invokeAjax: function() {
+   },
+
+   handleTimedOut: function() {
+      //server did not respond in 4 seconds... assume that there could have been
+      //an error or something, and allow requests to be processed again...
+      this.processingRequest = null;
+      this.processQueuedRequest();
+   },
+
+   fetchBuffer: function(offset) {
+      if ( this.buffer.isInRange(offset) &&
+         !this.buffer.isNearingLimit(offset)) {
+         return;
+      }
+      if (this.processingRequest) {
+          this.unprocessedRequest = new Rico.LiveGridRequest(offset);
+         return;
+      }
+      var bufferStartPos = this.buffer.getFetchOffset(offset);
+      this.processingRequest = new Rico.LiveGridRequest(offset);
+      this.processingRequest.bufferOffset = bufferStartPos;   
+      var fetchSize = this.buffer.getFetchSize(offset);
+      var partialLoaded = false;
+      var callParms = []; 
+      callParms.push(this.tableId + '_request');
+      callParms.push('id='        + this.tableId);
+      callParms.push('page_size=' + fetchSize);
+      callParms.push('offset='    + bufferStartPos);
+      if ( this.sortCol) {
+         callParms.push('sort_col='    + this.sortCol);
+         callParms.push('sort_dir='    + this.sortDir);
+      }
+      
+      for( var i=0 ; i < this.additionalParms.length ; i++ )
+         callParms.push(this.additionalParms[i]);
+      ajaxEngine.sendRequest.apply( ajaxEngine, callParms );
+        
+      this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), 20000 ); //todo: make as option
+   },
+
+   requestContentRefresh: function(contentOffset) {
+      this.fetchBuffer(contentOffset);
+   },
+
+   ajaxUpdate: function(ajaxResponse) {
+      try {
+         clearTimeout( this.timeoutHandler );
+         this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
+         this.viewPort.bufferChanged();
+      }
+      catch(err) {}
+      finally {this.processingRequest = null; }
+      this.processQueuedRequest();
+   },
+
+   processQueuedRequest: function() {
+      if (this.unprocessedRequest != null) {
+         this.requestContentRefresh(this.unprocessedRequest.requestOffset);
+         this.unprocessedRequest = null
+      }  
+   }
+ 
+};
+
+
+//-------------------- ricoLiveGridSort.js
+Rico.LiveGridSort = Class.create();
+
+Rico.LiveGridSort.prototype = {
+
+   initialize: function(headerTableId, options) {
+      this.headerTableId = headerTableId;
+      this.headerTable   = $(headerTableId);
+      this.setOptions(options);
+      this.applySortBehavior();
+
+      if ( this.options.sortCol ) {
+         this.setSortUI( this.options.sortCol, this.options.sortDir );
+      }
+   },
+
+   setSortUI: function( columnName, sortDirection ) {
+      var cols = this.options.columns;
+      for ( var i = 0 ; i < cols.length ; i++ ) {
+         if ( cols[i].name == columnName ) {
+            this.setColumnSort(i, sortDirection);
+            break;
+         }
+      }
+   },
+
+   setOptions: function(options) {
+      this.options = {
+         sortAscendImg:    'images/sort_asc.gif',
+         sortDescendImg:   'images/sort_desc.gif',
+         imageWidth:       9,
+         imageHeight:      5,
+         ajaxSortURLParms: []
+      }.extend(options);
+
+      // preload the images...
+      new Image().src = this.options.sortAscendImg;
+      new Image().src = this.options.sortDescendImg;
+
+      this.sort = options.sortHandler;
+      if ( !this.options.columns )
+         this.options.columns = this.introspectForColumnInfo();
+      else {
+         // allow client to pass { columns: [ ["a", true], ["b", false] ] }
+         // and convert to an array of Rico.TableColumn objs...
+         this.options.columns = this.convertToTableColumns(this.options.columns);
+      }
+   },
+
+   applySortBehavior: function() {
+      var headerRow   = this.headerTable.rows[0];
+      var headerCells = headerRow.cells;
+      for ( var i = 0 ; i < headerCells.length ; i++ ) {
+         this.addSortBehaviorToColumn( i, headerCells[i] );
+      }
+   },
+
+   addSortBehaviorToColumn: function( n, cell ) {
+      if ( this.options.columns[n].isSortable() ) {
+         cell.id            = this.headerTableId + '_' + n;
+         cell.style.cursor  = 'pointer';
+         cell.onclick       = this.headerCellClicked.bindAsEventListener(this);
+         cell.innerHTML     = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
+                           + '&nbsp;&nbsp;&nbsp;</span>';
+      }
+   },
+
+   // event handler....
+   headerCellClicked: function(evt) {
+      var eventTarget = evt.target ? evt.target : evt.srcElement;
+      var cellId = eventTarget.id;
+      var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 ));
+      var sortedColumnIndex = this.getSortedColumnIndex();
+      if ( sortedColumnIndex != -1 ) {
+         if ( sortedColumnIndex != columnNumber ) {
+            this.removeColumnSort(sortedColumnIndex);
+            this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
+         }
+         else
+            this.toggleColumnSort(sortedColumnIndex);
+      }
+      else
+         this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
+
+      if (this.options.sortHandler) {
+         this.options.sortHandler(this.options.columns[columnNumber]);
+      }
+   },
+
+   removeColumnSort: function(n) {
+      this.options.columns[n].setUnsorted();
+      this.setSortImage(n);
+   },
+
+   setColumnSort: function(n, direction) {
+      this.options.columns[n].setSorted(direction);
+      this.setSortImage(n);
+   },
+
+   toggleColumnSort: function(n) {
+      this.options.columns[n].toggleSort();
+      this.setSortImage(n);
+   },
+
+   setSortImage: function(n) {
+      var sortDirection = this.options.columns[n].getSortDirection();
+
+      var sortImageSpan = $( this.headerTableId + '_img_' + n );
+      if ( sortDirection == Rico.TableColumn.UNSORTED )
+         sortImageSpan.innerHTML = '&nbsp;&nbsp;';
+      else if ( sortDirection == Rico.TableColumn.SORT_ASC )
+         sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.imageWidth    + '" ' +
+                                                     'height="'+ this.options.imageHeight   + '" ' +
+                                                     'src="'   + this.options.sortAscendImg + '"/>';
+      else if ( sortDirection == Rico.TableColumn.SORT_DESC )
+         sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.imageWidth    + '" ' +
+                                                     'height="'+ this.options.imageHeight   + '" ' +
+                                                     'src="'   + this.options.sortDescendImg + '"/>';
+   },
+
+   getSortedColumnIndex: function() {
+      var cols = this.options.columns;
+      for ( var i = 0 ; i < cols.length ; i++ ) {
+         if ( cols[i].isSorted() )
+            return i;
+      }
+
+      return -1;
+   },
+
+   introspectForColumnInfo: function() {
+      var columns = new Array();
+      var headerRow   = this.headerTable.rows[0];
+      var headerCells = headerRow.cells;
+      for ( var i = 0 ; i < headerCells.length ; i++ )
+         columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
+      return columns;
+   },
+
+   convertToTableColumns: function(cols) {
+      var columns = new Array();
+      for ( var i = 0 ; i < cols.length ; i++ )
+         columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
+   },
+
+   deriveColumnNameFromCell: function(cell,columnNumber) {
+      var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
+      return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
+   }
+};
+
+Rico.TableColumn = Class.create();
+
+Rico.TableColumn.UNSORTED  = 0;
+Rico.TableColumn.SORT_ASC  = "ASC";
+Rico.TableColumn.SORT_DESC = "DESC";
+
+Rico.TableColumn.prototype = {
+   initialize: function(name, sortable) {
+      this.name        = name;
+      this.sortable    = sortable;
+      this.currentSort = Rico.TableColumn.UNSORTED;
+   },
+
+   isSortable: function() {
+      return this.sortable;
+   },
+
+   isSorted: function() {
+      return this.currentSort != Rico.TableColumn.UNSORTED;
+   },
+
+   getSortDirection: function() {
+      return this.currentSort;
+   },
+
+   toggleSort: function() {
+      if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
+         this.currentSort = Rico.TableColumn.SORT_ASC;
+      else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
+         this.currentSort = Rico.TableColumn.SORT_DESC;
+   },
+
+   setUnsorted: function(direction) {
+      this.setSorted(Rico.TableColumn.UNSORTED);
+   },
+
+   setSorted: function(direction) {
+      // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SET_DESC...
+      this.currentSort = direction;
+   }
+
+};
+
+
+//-------------------- ricoUtil.js
+
+var RicoUtil = {
+
+   getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
+      if ( arguments.length == 2 )
+         mozillaEquivalentCSS = cssProperty;
+
+      var el = $(htmlElement);
+      if ( el.currentStyle )
+         return el.currentStyle[cssProperty];
+      else
+         return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
+   },
+
+   createXmlDocument : function() {
+      if (document.implementation && document.implementation.createDocument) {
+         var doc = document.implementation.createDocument("", "", null);
+
+         if (doc.readyState == null) {
+            doc.readyState = 1;
+            doc.addEventListener("load", function () {
+               doc.readyState = 4;
+               if (typeof doc.onreadystatechange == "function")
+                  doc.onreadystatechange();
+            }, false);
+         }
+
+         return doc;
+      }
+
+      if (window.ActiveXObject)
+          return Try.these(
+            function() { return new ActiveXObject('MSXML2.DomDocument')   },
+            function() { return new ActiveXObject('Microsoft.DomDocument')},
+            function() { return new ActiveXObject('MSXML.DomDocument')    },
+            function() { return new ActiveXObject('MSXML3.DomDocument')   }
+          ) || false;
+
+      return null;
+   },
+
+   getContentAsString: function( parentNode ) {
+      return parentNode.xml != undefined ? 
+         this._getContentAsStringIE(parentNode) :
+         this._getContentAsStringMozilla(parentNode);
+   },
+
+   _getContentAsStringIE: function(parentNode) {
+      var contentStr = "";
+      for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
+         contentStr += parentNode.childNodes[i].xml;
+      return contentStr;
+   },
+
+   _getContentAsStringMozilla: function(parentNode) {
+      var xmlSerializer = new XMLSerializer();
+      var contentStr = "";
+      for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
+         contentStr += xmlSerializer.serializeToString(parentNode.childNodes[i]);
+      return contentStr;
+   },
+
+   toViewportPosition: function(element) {
+      return this._toAbsolute(element,true);
+   },
+
+   toDocumentPosition: function(element) {
+      return this._toAbsolute(element,false);
+   },
+
+   /**
+    *  Compute the elements position in terms of the window viewport
+    *  so that it can be compared to the position of the mouse (dnd)
+    *  This is additions of all the offsetTop,offsetLeft values up the
+    *  offsetParent hierarchy, ...taking into account any scrollTop,
+    *  scrollLeft values along the way...
+    *
+    * IE has a bug reporting a correct offsetLeft of elements within a
+    * a relatively positioned parent!!!
+    **/
+   _toAbsolute: function(element,accountForDocScroll) {
+
+      if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
+         return this._toAbsoluteMozilla(element,accountForDocScroll);
+
+      var x = 0;
+      var y = 0;
+      var parent = element;
+      while ( parent ) {
+
+         var borderXOffset = 0;
+         var borderYOffset = 0;
+         if ( parent != element ) {
+            var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
+            var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
+            borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
+            borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
+         }
+
+         x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
+         y += parent.offsetTop - parent.scrollTop + borderYOffset;
+         parent = parent.offsetParent;
+      }
+
+      if ( accountForDocScroll ) {
+         x -= this.docScrollLeft();
+         y -= this.docScrollTop();
+      }
+
+      return { x:x, y:y };
+   },
+
+   /**
+    *  Mozilla did not report all of the parents up the hierarchy via the
+    *  offsetParent property that IE did.  So for the calculation of the
+    *  offsets we use the offsetParent property, but for the calculation of
+    *  the scrollTop/scrollLeft adjustments we navigate up via the parentNode
+    *  property instead so as to get the scroll offsets...
+    *
+    **/
+   _toAbsoluteMozilla: function(element,accountForDocScroll) {
+      var x = 0;
+      var y = 0;
+      var parent = element;
+      while ( parent ) {
+         x += parent.offsetLeft;
+         y += parent.offsetTop;
+         parent = parent.offsetParent;
+      }
+
+      parent = element;
+      while ( parent &&
+              parent != document.body &&
+              parent != document.documentElement ) {
+         if ( parent.scrollLeft  )
+            x -= parent.scrollLeft;
+         if ( parent.scrollTop )
+            y -= parent.scrollTop;
+         parent = parent.parentNode;
+      }
+
+      if ( accountForDocScroll ) {
+         x -= this.docScrollLeft();
+         y -= this.docScrollTop();
+      }
+
+      return { x:x, y:y };
+   },
+
+   docScrollLeft: function() {
+      if ( window.pageXOffset )
+         return window.pageXOffset;
+      else if ( document.documentElement && document.documentElement.scrollLeft )
+         return document.documentElement.scrollLeft;
+      else if ( document.body )
+         return document.body.scrollLeft;
+      else
+         return 0;
+   },
+
+   docScrollTop: function() {
+      if ( window.pageYOffset )
+         return window.pageYOffset;
+      else if ( document.documentElement && document.documentElement.scrollTop )
+         return document.documentElement.scrollTop;
+      else if ( document.body )
+         return document.body.scrollTop;
+      else
+         return 0;
+   }
+
+};
Index: /branches/features/grailsUpgrade/web-app/js/prototype/scriptaculous.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/scriptaculous.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/scriptaculous.js	(revision 875)
@@ -0,0 +1,58 @@
+// script.aculo.us scriptaculous.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+var Scriptaculous = {
+  Version: '1.8.0',
+  require: function(libraryName) {
+    // inserting via DOM fails in Safari 2.0, so brute force approach
+    document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
+  },
+  REQUIRED_PROTOTYPE: '1.6.0',
+  load: function() {
+    function convertVersionString(versionString){
+      var r = versionString.split('.');
+      return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
+    }
+ 
+    if((typeof Prototype=='undefined') || 
+       (typeof Element == 'undefined') || 
+       (typeof Element.Methods=='undefined') ||
+       (convertVersionString(Prototype.Version) < 
+        convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
+       throw("script.aculo.us requires the Prototype JavaScript framework >= " +
+        Scriptaculous.REQUIRED_PROTOTYPE);
+    
+    $A(document.getElementsByTagName("script")).findAll( function(s) {
+      return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
+    }).each( function(s) {
+      var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
+      var includes = s.src.match(/\?.*load=([a-z,]*)/);
+      (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
+       function(include) { Scriptaculous.require(path+include+'.js') });
+    });
+  }
+}
+
+Scriptaculous.load();
Index: /branches/features/grailsUpgrade/web-app/js/prototype/slider.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/slider.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/slider.js	(revision 875)
@@ -0,0 +1,275 @@
+// script.aculo.us slider.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Marty Haught, Thomas Fuchs 
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+if (!Control) var Control = { };
+
+// options:
+//  axis: 'vertical', or 'horizontal' (default)
+//
+// callbacks:
+//  onChange(value)
+//  onSlide(value)
+Control.Slider = Class.create({
+  initialize: function(handle, track, options) {
+    var slider = this;
+    
+    if (Object.isArray(handle)) {
+      this.handles = handle.collect( function(e) { return $(e) });
+    } else {
+      this.handles = [$(handle)];
+    }
+    
+    this.track   = $(track);
+    this.options = options || { };
+
+    this.axis      = this.options.axis || 'horizontal';
+    this.increment = this.options.increment || 1;
+    this.step      = parseInt(this.options.step || '1');
+    this.range     = this.options.range || $R(0,1);
+    
+    this.value     = 0; // assure backwards compat
+    this.values    = this.handles.map( function() { return 0 });
+    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
+    this.options.startSpan = $(this.options.startSpan || null);
+    this.options.endSpan   = $(this.options.endSpan || null);
+
+    this.restricted = this.options.restricted || false;
+
+    this.maximum   = this.options.maximum || this.range.end;
+    this.minimum   = this.options.minimum || this.range.start;
+
+    // Will be used to align the handle onto the track, if necessary
+    this.alignX = parseInt(this.options.alignX || '0');
+    this.alignY = parseInt(this.options.alignY || '0');
+    
+    this.trackLength = this.maximumOffset() - this.minimumOffset();
+
+    this.handleLength = this.isVertical() ? 
+      (this.handles[0].offsetHeight != 0 ? 
+        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : 
+      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
+        this.handles[0].style.width.replace(/px$/,""));
+
+    this.active   = false;
+    this.dragging = false;
+    this.disabled = false;
+
+    if (this.options.disabled) this.setDisabled();
+
+    // Allowed values array
+    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
+    if (this.allowedValues) {
+      this.minimum = this.allowedValues.min();
+      this.maximum = this.allowedValues.max();
+    }
+
+    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
+    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
+    this.eventMouseMove = this.update.bindAsEventListener(this);
+
+    // Initialize handles in reverse (make sure first handle is active)
+    this.handles.each( function(h,i) {
+      i = slider.handles.length-1-i;
+      slider.setValue(parseFloat(
+        (Object.isArray(slider.options.sliderValue) ? 
+          slider.options.sliderValue[i] : slider.options.sliderValue) || 
+         slider.range.start), i);
+      h.makePositioned().observe("mousedown", slider.eventMouseDown);
+    });
+    
+    this.track.observe("mousedown", this.eventMouseDown);
+    document.observe("mouseup", this.eventMouseUp);
+    document.observe("mousemove", this.eventMouseMove);
+    
+    this.initialized = true;
+  },
+  dispose: function() {
+    var slider = this;    
+    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
+    Event.stopObserving(document, "mouseup", this.eventMouseUp);
+    Event.stopObserving(document, "mousemove", this.eventMouseMove);
+    this.handles.each( function(h) {
+      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
+    });
+  },
+  setDisabled: function(){
+    this.disabled = true;
+  },
+  setEnabled: function(){
+    this.disabled = false;
+  },  
+  getNearestValue: function(value){
+    if (this.allowedValues){
+      if (value >= this.allowedValues.max()) return(this.allowedValues.max());
+      if (value <= this.allowedValues.min()) return(this.allowedValues.min());
+      
+      var offset = Math.abs(this.allowedValues[0] - value);
+      var newValue = this.allowedValues[0];
+      this.allowedValues.each( function(v) {
+        var currentOffset = Math.abs(v - value);
+        if (currentOffset <= offset){
+          newValue = v;
+          offset = currentOffset;
+        } 
+      });
+      return newValue;
+    }
+    if (value > this.range.end) return this.range.end;
+    if (value < this.range.start) return this.range.start;
+    return value;
+  },
+  setValue: function(sliderValue, handleIdx){
+    if (!this.active) {
+      this.activeHandleIdx = handleIdx || 0;
+      this.activeHandle    = this.handles[this.activeHandleIdx];
+      this.updateStyles();
+    }
+    handleIdx = handleIdx || this.activeHandleIdx || 0;
+    if (this.initialized && this.restricted) {
+      if ((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
+        sliderValue = this.values[handleIdx-1];
+      if ((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
+        sliderValue = this.values[handleIdx+1];
+    }
+    sliderValue = this.getNearestValue(sliderValue);
+    this.values[handleIdx] = sliderValue;
+    this.value = this.values[0]; // assure backwards compat
+    
+    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
+      this.translateToPx(sliderValue);
+    
+    this.drawSpans();
+    if (!this.dragging || !this.event) this.updateFinished();
+  },
+  setValueBy: function(delta, handleIdx) {
+    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
+      handleIdx || this.activeHandleIdx || 0);
+  },
+  translateToPx: function(value) {
+    return Math.round(
+      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
+      (value - this.range.start)) + "px";
+  },
+  translateToValue: function(offset) {
+    return ((offset/(this.trackLength-this.handleLength) * 
+      (this.range.end-this.range.start)) + this.range.start);
+  },
+  getRange: function(range) {
+    var v = this.values.sortBy(Prototype.K); 
+    range = range || 0;
+    return $R(v[range],v[range+1]);
+  },
+  minimumOffset: function(){
+    return(this.isVertical() ? this.alignY : this.alignX);
+  },
+  maximumOffset: function(){
+    return(this.isVertical() ? 
+      (this.track.offsetHeight != 0 ? this.track.offsetHeight :
+        this.track.style.height.replace(/px$/,"")) - this.alignY : 
+      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
+        this.track.style.width.replace(/px$/,"")) - this.alignX);
+  },  
+  isVertical:  function(){
+    return (this.axis == 'vertical');
+  },
+  drawSpans: function() {
+    var slider = this;
+    if (this.spans)
+      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
+    if (this.options.startSpan)
+      this.setSpan(this.options.startSpan,
+        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
+    if (this.options.endSpan)
+      this.setSpan(this.options.endSpan, 
+        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
+  },
+  setSpan: function(span, range) {
+    if (this.isVertical()) {
+      span.style.top = this.translateToPx(range.start);
+      span.style.height = this.translateToPx(range.end - range.start + this.range.start);
+    } else {
+      span.style.left = this.translateToPx(range.start);
+      span.style.width = this.translateToPx(range.end - range.start + this.range.start);
+    }
+  },
+  updateStyles: function() {
+    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
+    Element.addClassName(this.activeHandle, 'selected');
+  },
+  startDrag: function(event) {
+    if (Event.isLeftClick(event)) {
+      if (!this.disabled){
+        this.active = true;
+        
+        var handle = Event.element(event);
+        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
+        var track = handle;
+        if (track==this.track) {
+          var offsets  = Position.cumulativeOffset(this.track); 
+          this.event = event;
+          this.setValue(this.translateToValue( 
+           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
+          ));
+          var offsets  = Position.cumulativeOffset(this.activeHandle);
+          this.offsetX = (pointer[0] - offsets[0]);
+          this.offsetY = (pointer[1] - offsets[1]);
+        } else {
+          // find the handle (prevents issues with Safari)
+          while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
+            handle = handle.parentNode;
+            
+          if (this.handles.indexOf(handle)!=-1) {
+            this.activeHandle    = handle;
+            this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
+            this.updateStyles();
+            
+            var offsets  = Position.cumulativeOffset(this.activeHandle);
+            this.offsetX = (pointer[0] - offsets[0]);
+            this.offsetY = (pointer[1] - offsets[1]);
+          }
+        }
+      }
+      Event.stop(event);
+    }
+  },
+  update: function(event) {
+   if (this.active) {
+      if (!this.dragging) this.dragging = true;
+      this.draw(event);
+      if (Prototype.Browser.WebKit) window.scrollBy(0,0);
+      Event.stop(event);
+   }
+  },
+  draw: function(event) {
+    var pointer = [Event.pointerX(event), Event.pointerY(event)];
+    var offsets = Position.cumulativeOffset(this.track);
+    pointer[0] -= this.offsetX + offsets[0];
+    pointer[1] -= this.offsetY + offsets[1];
+    this.event = event;
+    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
+    if (this.initialized && this.options.onSlide)
+      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
+  },
+  endDrag: function(event) {
+    if (this.active && this.dragging) {
+      this.finishDrag(event, true);
+      Event.stop(event);
+    }
+    this.active = false;
+    this.dragging = false;
+  },  
+  finishDrag: function(event, success) {
+    this.active = false;
+    this.dragging = false;
+    this.updateFinished();
+  },
+  updateFinished: function() {
+    if (this.initialized && this.options.onChange) 
+      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
+    this.event = null;
+  }
+});
Index: /branches/features/grailsUpgrade/web-app/js/prototype/sound.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/sound.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/sound.js	(revision 875)
@@ -0,0 +1,55 @@
+// script.aculo.us sound.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
+// Based on code created by Jules Gravinese (http://www.webveteran.com/)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+Sound = {
+  tracks: {},
+  _enabled: true,
+  template:
+    new Template('<embed style="height:0" id="sound_#{track}_#{id}" src="#{url}" loop="false" autostart="true" hidden="true"/>'),
+  enable: function(){
+    Sound._enabled = true;
+  },
+  disable: function(){
+    Sound._enabled = false;
+  },
+  play: function(url){
+    if(!Sound._enabled) return;
+    var options = Object.extend({
+      track: 'global', url: url, replace: false
+    }, arguments[1] || {});
+    
+    if(options.replace && this.tracks[options.track]) {
+      $R(0, this.tracks[options.track].id).each(function(id){
+        var sound = $('sound_'+options.track+'_'+id);
+        sound.Stop && sound.Stop();
+        sound.remove();
+      })
+      this.tracks[options.track] = null;
+    }
+      
+    if(!this.tracks[options.track])
+      this.tracks[options.track] = { id: 0 }
+    else
+      this.tracks[options.track].id++;
+      
+    options.id = this.tracks[options.track].id;
+    $$('body')[0].insert( 
+      Prototype.Browser.IE ? new Element('bgsound',{
+        id: 'sound_'+options.track+'_'+options.id,
+        src: options.url, loop: 1, autostart: true
+      }) : Sound.template.evaluate(options));
+  }
+};
+
+if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){
+  if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 }))
+    Sound.template = new Template('<object id="sound_#{track}_#{id}" width="0" height="0" type="audio/mpeg" data="#{url}"/>')
+  else
+    Sound.play = function(){}
+}
Index: /branches/features/grailsUpgrade/web-app/js/prototype/unittest.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/prototype/unittest.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/prototype/unittest.js	(revision 875)
@@ -0,0 +1,568 @@
+// script.aculo.us unittest.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+
+// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//           (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
+//           (c) 2005-2007 Michael Schuerig (http://www.schuerig.de/michael/)
+//
+// script.aculo.us is freely distributable under the terms of an MIT-style license.
+// For details, see the script.aculo.us web site: http://script.aculo.us/
+
+// experimental, Firefox-only
+Event.simulateMouse = function(element, eventName) {
+  var options = Object.extend({
+    pointerX: 0,
+    pointerY: 0,
+    buttons:  0,
+    ctrlKey:  false,
+    altKey:   false,
+    shiftKey: false,
+    metaKey:  false
+  }, arguments[2] || {});
+  var oEvent = document.createEvent("MouseEvents");
+  oEvent.initMouseEvent(eventName, true, true, document.defaultView, 
+    options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, 
+    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element));
+  
+  if(this.mark) Element.remove(this.mark);
+  this.mark = document.createElement('div');
+  this.mark.appendChild(document.createTextNode(" "));
+  document.body.appendChild(this.mark);
+  this.mark.style.position = 'absolute';
+  this.mark.style.top = options.pointerY + "px";
+  this.mark.style.left = options.pointerX + "px";
+  this.mark.style.width = "5px";
+  this.mark.style.height = "5px;";
+  this.mark.style.borderTop = "1px solid red;"
+  this.mark.style.borderLeft = "1px solid red;"
+  
+  if(this.step)
+    alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
+  
+  $(element).dispatchEvent(oEvent);
+};
+
+// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
+// You need to downgrade to 1.0.4 for now to get this working
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
+Event.simulateKey = function(element, eventName) {
+  var options = Object.extend({
+    ctrlKey: false,
+    altKey: false,
+    shiftKey: false,
+    metaKey: false,
+    keyCode: 0,
+    charCode: 0
+  }, arguments[2] || {});
+
+  var oEvent = document.createEvent("KeyEvents");
+  oEvent.initKeyEvent(eventName, true, true, window, 
+    options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
+    options.keyCode, options.charCode );
+  $(element).dispatchEvent(oEvent);
+};
+
+Event.simulateKeys = function(element, command) {
+  for(var i=0; i<command.length; i++) {
+    Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
+  }
+};
+
+var Test = {}
+Test.Unit = {};
+
+// security exception workaround
+Test.Unit.inspect = Object.inspect;
+
+Test.Unit.Logger = Class.create();
+Test.Unit.Logger.prototype = {
+  initialize: function(log) {
+    this.log = $(log);
+    if (this.log) {
+      this._createLogTable();
+    }
+  },
+  start: function(testName) {
+    if (!this.log) return;
+    this.testName = testName;
+    this.lastLogLine = document.createElement('tr');
+    this.statusCell = document.createElement('td');
+    this.nameCell = document.createElement('td');
+    this.nameCell.className = "nameCell";
+    this.nameCell.appendChild(document.createTextNode(testName));
+    this.messageCell = document.createElement('td');
+    this.lastLogLine.appendChild(this.statusCell);
+    this.lastLogLine.appendChild(this.nameCell);
+    this.lastLogLine.appendChild(this.messageCell);
+    this.loglines.appendChild(this.lastLogLine);
+  },
+  finish: function(status, summary) {
+    if (!this.log) return;
+    this.lastLogLine.className = status;
+    this.statusCell.innerHTML = status;
+    this.messageCell.innerHTML = this._toHTML(summary);
+    this.addLinksToResults();
+  },
+  message: function(message) {
+    if (!this.log) return;
+    this.messageCell.innerHTML = this._toHTML(message);
+  },
+  summary: function(summary) {
+    if (!this.log) return;
+    this.logsummary.innerHTML = this._toHTML(summary);
+  },
+  _createLogTable: function() {
+    this.log.innerHTML =
+    '<div id="logsummary"></div>' +
+    '<table id="logtable">' +
+    '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
+    '<tbody id="loglines"></tbody>' +
+    '</table>';
+    this.logsummary = $('logsummary')
+    this.loglines = $('loglines');
+  },
+  _toHTML: function(txt) {
+    return txt.escapeHTML().replace(/\n/g,"<br/>");
+  },
+  addLinksToResults: function(){ 
+    $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
+      td.title = "Run only this test"
+      Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
+    });
+    $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
+      td.title = "Run all tests"
+      Event.observe(td, 'click', function(){ window.location.search = "";});
+    });
+  }
+}
+
+Test.Unit.Runner = Class.create();
+Test.Unit.Runner.prototype = {
+  initialize: function(testcases) {
+    this.options = Object.extend({
+      testLog: 'testlog'
+    }, arguments[1] || {});
+    this.options.resultsURL = this.parseResultsURLQueryParameter();
+    this.options.tests      = this.parseTestsQueryParameter();
+    if (this.options.testLog) {
+      this.options.testLog = $(this.options.testLog) || null;
+    }
+    if(this.options.tests) {
+      this.tests = [];
+      for(var i = 0; i < this.options.tests.length; i++) {
+        if(/^test/.test(this.options.tests[i])) {
+          this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
+        }
+      }
+    } else {
+      if (this.options.test) {
+        this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
+      } else {
+        this.tests = [];
+        for(var testcase in testcases) {
+          if(/^test/.test(testcase)) {
+            this.tests.push(
+               new Test.Unit.Testcase(
+                 this.options.context ? ' -> ' + this.options.titles[testcase] : testcase, 
+                 testcases[testcase], testcases["setup"], testcases["teardown"]
+               ));
+          }
+        }
+      }
+    }
+    this.currentTest = 0;
+    this.logger = new Test.Unit.Logger(this.options.testLog);
+    setTimeout(this.runTests.bind(this), 1000);
+  },
+  parseResultsURLQueryParameter: function() {
+    return window.location.search.parseQuery()["resultsURL"];
+  },
+  parseTestsQueryParameter: function(){
+    if (window.location.search.parseQuery()["tests"]){
+        return window.location.search.parseQuery()["tests"].split(',');
+    };
+  },
+  // Returns:
+  //  "ERROR" if there was an error,
+  //  "FAILURE" if there was a failure, or
+  //  "SUCCESS" if there was neither
+  getResult: function() {
+    var hasFailure = false;
+    for(var i=0;i<this.tests.length;i++) {
+      if (this.tests[i].errors > 0) {
+        return "ERROR";
+      }
+      if (this.tests[i].failures > 0) {
+        hasFailure = true;
+      }
+    }
+    if (hasFailure) {
+      return "FAILURE";
+    } else {
+      return "SUCCESS";
+    }
+  },
+  postResults: function() {
+    if (this.options.resultsURL) {
+      new Ajax.Request(this.options.resultsURL, 
+        { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
+    }
+  },
+  runTests: function() {
+    var test = this.tests[this.currentTest];
+    if (!test) {
+      // finished!
+      this.postResults();
+      this.logger.summary(this.summary());
+      return;
+    }
+    if(!test.isWaiting) {
+      this.logger.start(test.name);
+    }
+    test.run();
+    if(test.isWaiting) {
+      this.logger.message("Waiting for " + test.timeToWait + "ms");
+      setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
+    } else {
+      this.logger.finish(test.status(), test.summary());
+      this.currentTest++;
+      // tail recursive, hopefully the browser will skip the stackframe
+      this.runTests();
+    }
+  },
+  summary: function() {
+    var assertions = 0;
+    var failures = 0;
+    var errors = 0;
+    var messages = [];
+    for(var i=0;i<this.tests.length;i++) {
+      assertions +=   this.tests[i].assertions;
+      failures   +=   this.tests[i].failures;
+      errors     +=   this.tests[i].errors;
+    }
+    return (
+      (this.options.context ? this.options.context + ': ': '') + 
+      this.tests.length + " tests, " + 
+      assertions + " assertions, " + 
+      failures   + " failures, " +
+      errors     + " errors");
+  }
+}
+
+Test.Unit.Assertions = Class.create();
+Test.Unit.Assertions.prototype = {
+  initialize: function() {
+    this.assertions = 0;
+    this.failures   = 0;
+    this.errors     = 0;
+    this.messages   = [];
+  },
+  summary: function() {
+    return (
+      this.assertions + " assertions, " + 
+      this.failures   + " failures, " +
+      this.errors     + " errors" + "\n" +
+      this.messages.join("\n"));
+  },
+  pass: function() {
+    this.assertions++;
+  },
+  fail: function(message) {
+    this.failures++;
+    this.messages.push("Failure: " + message);
+  },
+  info: function(message) {
+    this.messages.push("Info: " + message);
+  },
+  error: function(error) {
+    this.errors++;
+    this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
+  },
+  status: function() {
+    if (this.failures > 0) return 'failed';
+    if (this.errors > 0) return 'error';
+    return 'passed';
+  },
+  assert: function(expression) {
+    var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
+    try { expression ? this.pass() : 
+      this.fail(message); }
+    catch(e) { this.error(e); }
+  },
+  assertEqual: function(expected, actual) {
+    var message = arguments[2] || "assertEqual";
+    try { (expected == actual) ? this.pass() :
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
+        '", actual "' + Test.Unit.inspect(actual) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertInspect: function(expected, actual) {
+    var message = arguments[2] || "assertInspect";
+    try { (expected == actual.inspect()) ? this.pass() :
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) + 
+        '", actual "' + Test.Unit.inspect(actual) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertEnumEqual: function(expected, actual) {
+    var message = arguments[2] || "assertEnumEqual";
+    try { $A(expected).length == $A(actual).length && 
+      expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
+        this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + 
+          ', actual ' + Test.Unit.inspect(actual)); }
+    catch(e) { this.error(e); }
+  },
+  assertNotEqual: function(expected, actual) {
+    var message = arguments[2] || "assertNotEqual";
+    try { (expected != actual) ? this.pass() : 
+      this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertIdentical: function(expected, actual) { 
+    var message = arguments[2] || "assertIdentical"; 
+    try { (expected === actual) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + Test.Unit.inspect(actual) + '"'); } 
+    catch(e) { this.error(e); } 
+  },
+  assertNotIdentical: function(expected, actual) { 
+    var message = arguments[2] || "assertNotIdentical"; 
+    try { !(expected === actual) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + Test.Unit.inspect(actual) + '"'); } 
+    catch(e) { this.error(e); } 
+  },
+  assertNull: function(obj) {
+    var message = arguments[1] || 'assertNull'
+    try { (obj==null) ? this.pass() : 
+      this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertMatch: function(expected, actual) {
+    var message = arguments[2] || 'assertMatch';
+    var regex = new RegExp(expected);
+    try { (regex.exec(actual)) ? this.pass() :
+      this.fail(message + ' : regex: "' +  Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertHidden: function(element) {
+    var message = arguments[1] || 'assertHidden';
+    this.assertEqual("none", element.style.display, message);
+  },
+  assertNotNull: function(object) {
+    var message = arguments[1] || 'assertNotNull';
+    this.assert(object != null, message);
+  },
+  assertType: function(expected, actual) {
+    var message = arguments[2] || 'assertType';
+    try { 
+      (actual.constructor == expected) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + (actual.constructor) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertNotOfType: function(expected, actual) {
+    var message = arguments[2] || 'assertNotOfType';
+    try { 
+      (actual.constructor != expected) ? this.pass() : 
+      this.fail(message + ': expected "' + Test.Unit.inspect(expected) +  
+        '", actual "' + (actual.constructor) + '"'); }
+    catch(e) { this.error(e); }
+  },
+  assertInstanceOf: function(expected, actual) {
+    var message = arguments[2] || 'assertInstanceOf';
+    try { 
+      (actual instanceof expected) ? this.pass() : 
+      this.fail(message + ": object was not an instance of the expected type"); }
+    catch(e) { this.error(e); } 
+  },
+  assertNotInstanceOf: function(expected, actual) {
+    var message = arguments[2] || 'assertNotInstanceOf';
+    try { 
+      !(actual instanceof expected) ? this.pass() : 
+      this.fail(message + ": object was an instance of the not expected type"); }
+    catch(e) { this.error(e); } 
+  },
+  assertRespondsTo: function(method, obj) {
+    var message = arguments[2] || 'assertRespondsTo';
+    try {
+      (obj[method] && typeof obj[method] == 'function') ? this.pass() : 
+      this.fail(message + ": object doesn't respond to [" + method + "]"); }
+    catch(e) { this.error(e); }
+  },
+  assertReturnsTrue: function(method, obj) {
+    var message = arguments[2] || 'assertReturnsTrue';
+    try {
+      var m = obj[method];
+      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+      m() ? this.pass() : 
+      this.fail(message + ": method returned false"); }
+    catch(e) { this.error(e); }
+  },
+  assertReturnsFalse: function(method, obj) {
+    var message = arguments[2] || 'assertReturnsFalse';
+    try {
+      var m = obj[method];
+      if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)];
+      !m() ? this.pass() : 
+      this.fail(message + ": method returned true"); }
+    catch(e) { this.error(e); }
+  },
+  assertRaise: function(exceptionName, method) {
+    var message = arguments[2] || 'assertRaise';
+    try { 
+      method();
+      this.fail(message + ": exception expected but none was raised"); }
+    catch(e) {
+      ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e); 
+    }
+  },
+  assertElementsMatch: function() {
+    var expressions = $A(arguments), elements = $A(expressions.shift());
+    if (elements.length != expressions.length) {
+      this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions');
+      return false;
+    }
+    elements.zip(expressions).all(function(pair, index) {
+      var element = $(pair.first()), expression = pair.last();
+      if (element.match(expression)) return true;
+      this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect());
+    }.bind(this)) && this.pass();
+  },
+  assertElementMatches: function(element, expression) {
+    this.assertElementsMatch([element], expression);
+  },
+  benchmark: function(operation, iterations) {
+    var startAt = new Date();
+    (iterations || 1).times(operation);
+    var timeTaken = ((new Date())-startAt);
+    this.info((arguments[2] || 'Operation') + ' finished ' + 
+       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+    return timeTaken;
+  },
+  _isVisible: function(element) {
+    element = $(element);
+    if(!element.parentNode) return true;
+    this.assertNotNull(element);
+    if(element.style && Element.getStyle(element, 'display') == 'none')
+      return false;
+    
+    return this._isVisible(element.parentNode);
+  },
+  assertNotVisible: function(element) {
+    this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
+  },
+  assertVisible: function(element) {
+    this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
+  },
+  benchmark: function(operation, iterations) {
+    var startAt = new Date();
+    (iterations || 1).times(operation);
+    var timeTaken = ((new Date())-startAt);
+    this.info((arguments[2] || 'Operation') + ' finished ' + 
+       iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+    return timeTaken;
+  }
+}
+
+Test.Unit.Testcase = Class.create();
+Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
+  initialize: function(name, test, setup, teardown) {
+    Test.Unit.Assertions.prototype.initialize.bind(this)();
+    this.name           = name;
+    
+    if(typeof test == 'string') {
+      test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,');
+      test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)');
+      this.test = function() {
+        eval('with(this){'+test+'}');
+      }
+    } else {
+      this.test = test || function() {};
+    }
+    
+    this.setup          = setup || function() {};
+    this.teardown       = teardown || function() {};
+    this.isWaiting      = false;
+    this.timeToWait     = 1000;
+  },
+  wait: function(time, nextPart) {
+    this.isWaiting = true;
+    this.test = nextPart;
+    this.timeToWait = time;
+  },
+  run: function() {
+    try {
+      try {
+        if (!this.isWaiting) this.setup.bind(this)();
+        this.isWaiting = false;
+        this.test.bind(this)();
+      } finally {
+        if(!this.isWaiting) {
+          this.teardown.bind(this)();
+        }
+      }
+    }
+    catch(e) { this.error(e); }
+  }
+});
+
+// *EXPERIMENTAL* BDD-style testing to please non-technical folk
+// This draws many ideas from RSpec http://rspec.rubyforge.org/
+
+Test.setupBDDExtensionMethods = function(){
+  var METHODMAP = {
+    shouldEqual:     'assertEqual',
+    shouldNotEqual:  'assertNotEqual',
+    shouldEqualEnum: 'assertEnumEqual',
+    shouldBeA:       'assertType',
+    shouldNotBeA:    'assertNotOfType',
+    shouldBeAn:      'assertType',
+    shouldNotBeAn:   'assertNotOfType',
+    shouldBeNull:    'assertNull',
+    shouldNotBeNull: 'assertNotNull',
+    
+    shouldBe:        'assertReturnsTrue',
+    shouldNotBe:     'assertReturnsFalse',
+    shouldRespondTo: 'assertRespondsTo'
+  };
+  var makeAssertion = function(assertion, args, object) { 
+   	this[assertion].apply(this,(args || []).concat([object]));
+  }
+  
+  Test.BDDMethods = {};   
+  $H(METHODMAP).each(function(pair) { 
+    Test.BDDMethods[pair.key] = function() { 
+       var args = $A(arguments); 
+       var scope = args.shift(); 
+       makeAssertion.apply(scope, [pair.value, args, this]); }; 
+  });
+  
+  [Array.prototype, String.prototype, Number.prototype, Boolean.prototype].each(
+    function(p){ Object.extend(p, Test.BDDMethods) }
+  );
+}
+
+Test.context = function(name, spec, log){
+  Test.setupBDDExtensionMethods();
+  
+  var compiledSpec = {};
+  var titles = {};
+  for(specName in spec) {
+    switch(specName){
+      case "setup":
+      case "teardown":
+        compiledSpec[specName] = spec[specName];
+        break;
+      default:
+        var testName = 'test'+specName.gsub(/\s+/,'-').camelize();
+        var body = spec[specName].toString().split('\n').slice(1);
+        if(/^\{/.test(body[0])) body = body.slice(1);
+        body.pop();
+        body = body.map(function(statement){ 
+          return statement.strip()
+        });
+        compiledSpec[testName] = body.join('\n');
+        titles[testName] = specName;
+    }
+  }
+  new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name });
+};
Index: /branches/features/grailsUpgrade/web-app/js/taskQuickSearchPane.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/taskQuickSearchPane.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/taskQuickSearchPane.js	(revision 875)
@@ -0,0 +1,33 @@
+
+function updateQuickSearchSelection() {
+    var personsTasksSelectionIds = ['personLabel', 'personSelection', 'completedLabel', 'completedSelection'];
+    var helpBalloonSpanIds = ['allTasksHelp', 'personsTasksHelp', 'personsImmediateCalloutsHelp'];
+    var val = $("quickSearchSelect").value;
+
+    $A(HelpBalloon._balloons).invoke('hide'); // Hide any open balloons.
+    helpBalloonSpanIds.each(Element.hide); // Hide all help icons.
+
+    switch(val)
+    {
+        case 'allTasks':
+            showUtil('allTasksHelp');
+            hideArrayUtil(personsTasksSelectionIds);
+            break;
+        case 'personsTasks':
+            showUtil('personsTasksHelp');
+            showArrayUtil(personsTasksSelectionIds);
+            break;
+        case 'personsImmediateCallouts':
+            showUtil('personsImmediateCalloutsHelp');
+            showArrayUtil(personsTasksSelectionIds);
+            break;
+    }
+
+}
+
+Event.observe(window, 'load', function() {
+    updateQuickSearchSelection(); // Initial page load.
+    $A(HelpBalloon._balloons).invoke('show'); // Work around for offset balloon when using a pane in IE.
+    $A(HelpBalloon._balloons).invoke('hide'); // Work around for offset balloon when using a pane in IE.
+    $("quickSearchSelect").observe('change', updateQuickSearchSelection); // Register onchange handler.
+});
Index: /branches/features/grailsUpgrade/web-app/js/taskShow.js
===================================================================
--- /branches/features/grailsUpgrade/web-app/js/taskShow.js	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/js/taskShow.js	(revision 875)
@@ -0,0 +1,131 @@
+
+var submit_confirmResult = true
+
+function showButton(button) {
+    button.show(600, function() {
+        if(jQuery.browser.msie) {
+            jQuery(this).get(0).style.removeAttribute('filter'); // Remove blur/fuzzy text in IE.
+        }
+    });
+}
+
+function createEntryFormInit(target, listContainer, button) {
+
+    // Show.
+    target.slideDown(800);
+    // Scroll the window.
+    jQuery('html,body').animate({scrollTop: target.offset().top - 70}, 900, function() {
+        target.find(':input[name="comment"]').focus();
+    });
+    // Register 'submit_*' input button click handlers.
+    target.find('input[name^="submit_"]').click(function(e){
+        target.find(':input[name="submitAction"]').val(jQuery(this).attr('name'));
+        target.find('form:first').submit();
+    });
+    // Redirect form submit to use our function.
+    var eventData = {listContainer:listContainer, source:target, button:button};
+    target.find('form:first').submit(eventData, submitCreateEntryForm);
+    // Register the close img click handler.
+    target.find('.pane_close img').click(function(){
+        target.slideUp(600);
+        showButton(button);
+    });
+
+}
+
+// Submit a create Entry form via AJAX.
+function submitCreateEntryForm(event) {
+
+    event.preventDefault();
+
+    if(submit_confirmResult == false) {
+        submit_confirmResult = true
+        return false;
+    }
+
+    var actionUrl = getContextPath()+"/entryDetailed/ajaxSave/";
+    var listContainer = event.data.listContainer;
+    var source = event.data.source;
+    var button = event.data.button;
+    var form = source.find('form:first');
+
+    // On success reload listContainer.
+    function success(data, textStatus, jqXHR) {
+        source.hide();
+        applyElementUpdates(data);
+        showButton(button);
+    }
+
+    // On create failure controller sets 403 and returns the form template.
+    function error(jqXHR, textStatus, errorThrown) {
+        if(jqXHR.status == 403 && jqXHR.responseText) {
+            source.html(jqXHR.responseText);
+            createEntryFormInit(source, listContainer, button);
+        }
+        else {
+            source.html(savedHtml);
+            source.prepend(errorIndication(jqXHR, textStatus, errorThrown).show()).slideDown(600);
+            // Scroll the window.
+            jQuery('html,body').animate({scrollTop: source.offset().top - 70}, 900, function() {
+                source.find(':input[name="comment"]').focus();
+            });
+        }
+    }
+
+    // Start.
+    var savedHtml = source.children().detach();
+    var params = form.serializeArray();
+    params.push({name:'target', value:listContainer.selector});
+    source.html(loadingIndication().show()).slideDown(600);
+
+    jQuery.ajax({
+        url: actionUrl,
+        data: params,
+        type: 'POST',
+        dataType: 'json',
+        success: success,
+        error: error
+    });
+}
+
+// Get a create Entry form via AJAX.
+// @listContainer Container object to reload list into.
+// @button Button object used to trigger this function.
+// @params Params map to pass to actionUrl.
+// @params.target Selector indicating target to load response into.
+function getCreateEntryForm(listContainer, button, params) {
+
+    var actionUrl = getContextPath()+"/entryDetailed/ajaxCreate/";
+    var target = jQuery(params.target);
+
+    // On success load target.
+    function success(data, textStatus, jqXHR) {
+        applyElementUpdates(data);
+        createEntryFormInit(target, listContainer, button);
+    }
+
+    // On error show controller responseText or show default error.
+    function error(jqXHR, textStatus, errorThrown) {
+        if(jqXHR.status == 403 && jqXHR.responseText) {
+            target.html(jqXHR.responseText);
+        }
+        else {
+            target.html(errorIndication(jqXHR, textStatus, errorThrown).show());
+        }
+        showButton(button);
+    }
+
+    // Start.
+    button.hide(600);
+    target.html(loadingIndication().show()).slideDown(600);
+
+    jQuery.ajax({
+        url: actionUrl,
+        data: params,
+        type: 'POST',
+        dataType: 'json',
+        success: success,
+        error: error
+    });
+}
+
Index: /branches/features/grailsUpgrade/web-app/reports/assetDetail.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/assetDetail.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/assetDetail.jrxml	(revision 875)
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="595" pageHeight="842" whenNoDataType="NoDataSection" columnWidth="577" leftMargin="9" rightMargin="9" topMargin="9" bottomMargin="9" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.5"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="0"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="GroupHeader" isDefault="false" hAlign="Center">
+		<box topPadding="0" bottomPadding="0">
+			<topPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="DetailBorder" isDefault="false">
+		<box topPadding="2" leftPadding="1" bottomPadding="2" rightPadding="1">
+			<topPen lineWidth="0.5"/>
+			<leftPen lineWidth="0.5"/>
+			<bottomPen lineWidth="0.5"/>
+			<rightPen lineWidth="0.5"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<queryString language="SQL">
+			<![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]>
+		</queryString>
+		<field name="description" class="java.lang.String"/>
+		<field name="name" class="java.lang.String"/>
+		<field name="comment" class="java.lang.String"/>
+		<field name="attribValue" class="java.lang.String"/>
+		<field name="attribType" class="java.lang.String"/>
+		<group name="assetName">
+			<groupExpression><![CDATA[$F{name}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="section" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<parameter name="site" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="name" class="java.lang.String"/>
+	<field name="description" class="java.lang.String"/>
+	<field name="attribValue" class="java.lang.String"/>
+	<field name="attribType" class="java.lang.String"/>
+	<field name="comment" class="java.lang.String"/>
+	<group name="assetName" keepTogether="true">
+		<groupExpression><![CDATA[$F{name}]]></groupExpression>
+		<groupHeader>
+			<band height="52">
+				<textField isStretchWithOverflow="true" isBlankWhenNull="true">
+					<reportElement stretchType="RelativeToTallestObject" x="9" y="24" width="331" height="20" isPrintWhenDetailOverflows="true"/>
+					<textElement>
+						<font fontName="Serif" size="8"/>
+					</textElement>
+					<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+				</textField>
+				<textField isStretchWithOverflow="true">
+					<reportElement stretchType="RelativeToTallestObject" mode="Opaque" x="9" y="4" width="331" height="20" isPrintWhenDetailOverflows="true" backcolor="#FFFF33"/>
+					<textElement>
+						<font fontName="Serif" size="10" isBold="true"/>
+					</textElement>
+					<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+				</textField>
+				<textField isStretchWithOverflow="true">
+					<reportElement stretchType="RelativeToTallestObject" x="352" y="12" width="203" height="40" isPrintWhenDetailOverflows="true"/>
+					<textElement>
+						<font fontName="Serif" size="8"/>
+					</textElement>
+					<textFieldExpression class="java.lang.String"><![CDATA[$F{comment}]]></textFieldExpression>
+				</textField>
+			</band>
+		</groupHeader>
+		<groupFooter>
+			<band/>
+		</groupFooter>
+	</group>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="60" splitType="Stretch">
+			<textField isStretchWithOverflow="true">
+				<reportElement key="staticText-1" stretchType="RelativeToTallestObject" x="352" y="9" width="225" height="20" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="352" y="29" width="225" height="15" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif" size="10"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$P{site}+", "+"Section: "+$P{section}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="24" splitType="Stretch">
+			<printWhenExpression><![CDATA[$F{attribValue}]]></printWhenExpression>
+			<elementGroup>
+				<textField isStretchWithOverflow="true">
+					<reportElement style="DetailBorder" stretchType="RelativeToTallestObject" x="138" y="2" width="288" height="20" isPrintWhenDetailOverflows="true"/>
+					<textElement textAlignment="Center" verticalAlignment="Middle">
+						<font fontName="Serif" size="8"/>
+					</textElement>
+					<textFieldExpression class="java.lang.String"><![CDATA[$F{attribValue}]]></textFieldExpression>
+				</textField>
+				<textField isStretchWithOverflow="true">
+					<reportElement stretchType="RelativeToTallestObject" x="9" y="2" width="129" height="20" isPrintWhenDetailOverflows="true"/>
+					<textElement>
+						<font fontName="Serif" size="8" isBold="true" isUnderline="false"/>
+					</textElement>
+					<textFieldExpression class="java.lang.String"><![CDATA[$F{attribType}+":"]]></textFieldExpression>
+				</textField>
+			</elementGroup>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Stretch">
+			<textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy">
+				<reportElement stretchType="RelativeToTallestObject" x="50" y="2" width="200" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" evaluationTime="Report">
+				<reportElement stretchType="RelativeToTallestObject" x="537" y="14" width="40" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="50" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="50" y="14" width="200" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="0" y="14" width="50" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="457" y="14" width="80" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<textField isStretchWithOverflow="true" evaluationTime="Report">
+				<reportElement stretchType="RelativeToTallestObject" x="537" y="14" width="40" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy">
+				<reportElement stretchType="RelativeToTallestObject" x="50" y="2" width="200" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="50" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="0" y="14" width="50" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="50" y="14" width="200" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement stretchType="RelativeToTallestObject" x="457" y="14" width="80" height="12" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<printWhenExpression><![CDATA[""]]></printWhenExpression>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="555" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="555" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/assetRegister.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/assetRegister.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/assetRegister.jrxml	(revision 875)
@@ -0,0 +1,509 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="824" leftMargin="9" rightMargin="9" topMargin="9" bottomMargin="9" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.5"/>
+	<property name="ireport.x" value="15"/>
+	<property name="ireport.y" value="729"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="table" isDefault="false">
+		<box>
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="1.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="1.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#F0F8FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#BFE1FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" pattern="">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<queryString language="SQL">
+			<![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]>
+		</queryString>
+		<field name="name" class="java.lang.String"/>
+		<field name="description" class="java.lang.String"/>
+		<field name="comment" class="java.lang.String"/>
+		<field name="Serial Number" class="java.lang.String"/>
+		<field name="Model Number" class="java.lang.String"/>
+		<field name="Manufacturer" class="java.lang.String"/>
+		<field name="ecr" class="java.lang.String"/>
+		<field name="Risk Level" class="java.lang.String"/>
+		<field name="Safe Work Procedure" class="java.lang.String"/>
+		<field name="Regulatory Requirement" class="java.lang.String"/>
+		<field name="Maintenance % Completion" class="java.lang.String"/>
+		<field name="Registration Required" class="java.lang.String"/>
+		<field name="Registration Expiry Date" class="java.lang.String"/>
+		<field name="Asset Number" class="java.lang.String"/>
+		<group name="assetName">
+			<groupExpression><![CDATA[$F{name}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="dataList" class="java.util.List"/>
+	<field name="attribTypes" class="java.util.List"/>
+	<field name="site" class="java.lang.Object"/>
+	<field name="section" class="java.lang.Object"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="57" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="398" y="14" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField>
+				<reportElement x="398" y="34" width="340" height="15" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Center">
+					<font fontName="Serif" size="10"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$F{site}.name+", "+"Section: "+$F{section}.name]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="492" splitType="Immediate">
+			<componentElement>
+				<reportElement key="table" style="table" x="2" y="2" width="820" height="488"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="45">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="45" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<text><![CDATA[#]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:columnFooter height="2" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="45" height="2"/>
+								<textElement/>
+								<text><![CDATA[]]></text>
+							</staticText>
+						</jr:columnFooter>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="2" y="0" width="41" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Asset Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="96" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Asset]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" stretchType="RelativeToTallestObject" mode="Opaque" x="2" y="0" width="96" height="20" isPrintWhenDetailOverflows="true" backcolor="#D2EFF7"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+							</textField>
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" stretchType="RelativeToTallestObject" x="2" y="20" width="96" height="15" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="90">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="86" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Comment]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="86" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{comment}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="55">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="51" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Serial Number]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="51" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Serial Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Model Number]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="36" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Model Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="65">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="2" y="0" width="61" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Manufacturer]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="2" y="0" width="61" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Manufacturer}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="63">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="59" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Equipment Criticality (ecr)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="63" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{ecr}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="50">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Risk Level]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Risk Level}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Safe Work Procedure]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Safe Work Procedure}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="50">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Regulatory Requirement (Y/N)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Regulatory Requirement}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Maintenance % Completion]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Maintenance % Completion}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Registration Required (Y/N)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Registration Required}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="50">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Registration Expiry Date]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Registration Expiry Date}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Prevent">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement x="0" y="30" width="824" height="91"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Asset Extended Attributes: \n"+$F{attribTypes}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="824" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="824" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="18"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/equipmentRegisterFinancial.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/equipmentRegisterFinancial.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/equipmentRegisterFinancial.jrxml	(revision 875)
@@ -0,0 +1,479 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="824" leftMargin="9" rightMargin="9" topMargin="9" bottomMargin="9" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true" isIgnorePagination="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.5"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="644"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="table" isDefault="false">
+		<pen lineWidth="0.5"/>
+		<box>
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="1.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="1.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#F0F8FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#BFE1FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" pattern="">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_GH" isDefault="false" mode="Opaque" backcolor="#D2EFF7"/>
+	<subDataset name="dataset1">
+		<queryString language="SQL">
+			<![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]>
+		</queryString>
+		<field name="name" class="java.lang.String"/>
+		<field name="description" class="java.lang.String"/>
+		<field name="comment" class="java.lang.String"/>
+		<field name="Serial Number" class="java.lang.String"/>
+		<field name="Model Number" class="java.lang.String"/>
+		<field name="Manufacturer" class="java.lang.String"/>
+		<field name="ecr" class="java.lang.String"/>
+		<field name="Risk Level" class="java.lang.String"/>
+		<field name="Safe Work Procedure" class="java.lang.String"/>
+		<field name="Regulatory Requirement" class="java.lang.String"/>
+		<field name="Maintenance % Completion" class="java.lang.String"/>
+		<field name="Registration Required" class="java.lang.String"/>
+		<field name="Registration Expiry Date" class="java.lang.String"/>
+		<field name="assetName" class="java.lang.String"/>
+		<field name="Asset Number" class="java.lang.String"/>
+		<field name="Location Description" class="java.lang.String"/>
+		<field name="Asset Condition" class="java.lang.String"/>
+		<group name="assetName">
+			<groupExpression><![CDATA[$F{assetName}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="dataList" class="java.util.List"/>
+	<field name="attribTypes" class="java.lang.String"/>
+	<field name="assetsWithoutEquipment" class="java.lang.String"/>
+	<field name="site" class="java.lang.Object"/>
+	<field name="section" class="java.lang.Object"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="57" splitType="Stretch">
+			<printWhenExpression><![CDATA[false]]></printWhenExpression>
+			<textField>
+				<reportElement key="staticText-1" x="398" y="14" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField>
+				<reportElement x="398" y="34" width="340" height="15" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Center">
+					<font fontName="Serif" size="10"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$F{site}.name+", "+"Section: "+$F{section}.name]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="492" splitType="Immediate">
+			<componentElement>
+				<reportElement key="table" style="table" x="0" y="0" width="824" height="492"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="45">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="45" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10"/>
+								</textElement>
+								<text><![CDATA[#]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:columnFooter height="2" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="45" height="2"/>
+								<textElement/>
+								<text><![CDATA[]]></text>
+							</staticText>
+						</jr:columnFooter>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="45" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Asset Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="100" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Asset]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" mode="Transparent" x="0" y="0" width="100" height="36" isPrintWhenDetailOverflows="true" backcolor="#D2EFF7"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="false"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{assetName}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="90">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="90" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Description]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="90" height="36">
+									<printWhenExpression><![CDATA[$F{name}.equals('   Asset Details')]]></printWhenExpression>
+								</reportElement>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="100" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Sub Asset]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" mode="Transparent" x="0" y="0" width="100" height="36" isPrintWhenDetailOverflows="true" backcolor="#D2EFF7">
+									<printWhenExpression><![CDATA[!$F{name}.equals('   Asset Details')]]></printWhenExpression>
+								</reportElement>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="70">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="70" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Serial Number]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="70" height="36" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Serial Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="60" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Model Number]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="60" height="36" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Model Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="75">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="75" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Manufacturer]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="75" height="36" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Manufacturer}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="63">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="63" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Location]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="63" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Location Description}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="70">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="70" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Equipment Criticality]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="70" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{ecr}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="60" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Condition]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="60" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Asset Condition}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Prevent">
+			<printWhenExpression><![CDATA[false]]></printWhenExpression>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<printWhenExpression><![CDATA[false]]></printWhenExpression>
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<printWhenExpression><![CDATA[false]]></printWhenExpression>
+			<textField isStretchWithOverflow="true">
+				<reportElement positionType="Float" stretchType="RelativeToTallestObject" x="13" y="36" width="824" height="36" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["AssetSubItem Extended Attributes: \n"+$F{attribTypes}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="242" y="0" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary"]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement positionType="Float" stretchType="RelativeToTallestObject" x="13" y="100" width="824" height="26" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{assetsWithoutEquipment}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement positionType="Float" stretchType="RelativeToTallestObject" x="13" y="81" width="824" height="19" isPrintWhenDetailOverflows="true" forecolor="#000000">
+					<printWhenExpression><![CDATA[$F{assetsWithoutEquipment}]]></printWhenExpression>
+				</reportElement>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["The following assets have no sub assets (equipment):"]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="824" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="824" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="18"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/equipmentRegisterOhs.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/equipmentRegisterOhs.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/equipmentRegisterOhs.jrxml	(revision 875)
@@ -0,0 +1,560 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="824" leftMargin="9" rightMargin="9" topMargin="9" bottomMargin="9" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.5"/>
+	<property name="ireport.x" value="337"/>
+	<property name="ireport.y" value="0"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="table" isDefault="false">
+		<pen lineWidth="0.5"/>
+		<box>
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="1.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="1.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#F0F8FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#BFE1FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" pattern="">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_GH" isDefault="false" mode="Opaque" backcolor="#D2EFF7"/>
+	<subDataset name="dataset1">
+		<queryString language="SQL">
+			<![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]>
+		</queryString>
+		<field name="name" class="java.lang.String"/>
+		<field name="description" class="java.lang.String"/>
+		<field name="comment" class="java.lang.String"/>
+		<field name="Serial Number" class="java.lang.String"/>
+		<field name="Model Number" class="java.lang.String"/>
+		<field name="Manufacturer" class="java.lang.String"/>
+		<field name="ecr" class="java.lang.String"/>
+		<field name="Risk Level" class="java.lang.String"/>
+		<field name="Safe Work Procedure" class="java.lang.String"/>
+		<field name="Regulatory Requirement" class="java.lang.String"/>
+		<field name="Regulatory Task Completion" class="java.lang.String"/>
+		<field name="Registration Required" class="java.lang.String"/>
+		<field name="Registration Expiry Date" class="java.lang.String"/>
+		<field name="assetName" class="java.lang.String"/>
+		<field name="Asset Number" class="java.lang.String"/>
+		<group name="assetName">
+			<groupExpression><![CDATA[$F{assetName}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="dataList" class="java.util.List"/>
+	<field name="attribTypes" class="java.lang.String"/>
+	<field name="assetsWithoutEquipment" class="java.lang.String"/>
+	<field name="site" class="java.lang.Object"/>
+	<field name="section" class="java.lang.Object"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="57" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="398" y="5" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField>
+				<reportElement x="398" y="25" width="340" height="15" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Center">
+					<font fontName="Serif" size="10"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$F{site}.name+", "+"Section: "+$F{section}.name]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="398" y="40" width="340" height="12"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{startDateString}+" to "+$P{endDateString}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="492" splitType="Immediate">
+			<componentElement>
+				<reportElement key="table" style="table" x="2" y="2" width="820" height="488"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="45">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="45" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10"/>
+								</textElement>
+								<text><![CDATA[#]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:columnFooter height="2" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="45" height="2"/>
+								<textElement/>
+								<text><![CDATA[]]></text>
+							</staticText>
+						</jr:columnFooter>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField>
+								<reportElement x="2" y="0" width="41" height="36"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Asset Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="100" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Asset]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" mode="Opaque" x="2" y="0" width="96" height="18" isPrintWhenDetailOverflows="true" backcolor="#D2EFF7">
+									<printWhenExpression><![CDATA[$F{name}.equals('   Asset Details')]]></printWhenExpression>
+								</reportElement>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="false"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{assetName}]]></textFieldExpression>
+							</textField>
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" x="2" y="18" width="96" height="18" isPrintWhenDetailOverflows="true">
+									<printWhenExpression><![CDATA[$F{name}.equals('   Asset Details')]]></printWhenExpression>
+								</reportElement>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="96" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<text><![CDATA[Sub Asset]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" mode="Opaque" x="2" y="0" width="96" height="18" isPrintWhenDetailOverflows="true" backcolor="#D2EFF7">
+									<printWhenExpression><![CDATA[!$F{name}.equals('   Asset Details')]]></printWhenExpression>
+								</reportElement>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+							</textField>
+							<textField isStretchWithOverflow="true">
+								<reportElement positionType="Float" x="2" y="18" width="96" height="18" isPrintWhenDetailOverflows="true">
+									<printWhenExpression><![CDATA[!$F{name}.equals('   Asset Details')]]></printWhenExpression>
+								</reportElement>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="55">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="51" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Serial Number]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="51" height="36" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Serial Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Model Number]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Model Number}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="65">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="61" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Manufacturer]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="61" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Manufacturer}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="63">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="59" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Equipment Criticality (ecr)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="59" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{ecr}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="50">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Risk Level]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Risk Level}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Safe Work Procedure]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Safe Work Procedure}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="50">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Regulatory Requirement]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Regulatory Requirement}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Regulatory Task Complete]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Regulatory Task Completion}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="60">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Registration Required (Y/N)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="56" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Registration Required}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="50">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Registration Expiry Date]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="36" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="46" height="35" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{Registration Expiry Date}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Prevent">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField isStretchWithOverflow="true">
+				<reportElement positionType="Float" stretchType="RelativeToTallestObject" x="13" y="36" width="824" height="36" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["AssetSubItem Extended Attributes: \n"+$F{attribTypes}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="242" y="0" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary"]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement positionType="Float" stretchType="RelativeToTallestObject" x="13" y="100" width="824" height="26" isPrintWhenDetailOverflows="true"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{assetsWithoutEquipment}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement positionType="Float" stretchType="RelativeToTallestObject" x="13" y="81" width="824" height="19" isPrintWhenDetailOverflows="true" forecolor="#000000">
+					<printWhenExpression><![CDATA[$F{assetsWithoutEquipment}]]></printWhenExpression>
+				</reportElement>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["The following assets have no sub assets (equipment):"]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="824" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="824" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="18"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/immediateCallouts.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/immediateCallouts.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/immediateCallouts.jrxml	(revision 875)
@@ -0,0 +1,368 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="782" leftMargin="30" rightMargin="30" topMargin="20" bottomMargin="20" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="1109"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<style name="table" isDefault="false" fill="Solid" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="0.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#C7C7C7" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="10" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+		<conditionalStyle>
+			<conditionExpression><![CDATA[new Boolean($V{REPORT_COUNT}.intValue()%2==0)]]></conditionExpression>
+			<style isDefault="false" style="table_TD" backcolor="#F7F7F7"/>
+		</conditionalStyle>
+	</style>
+	<style name="table_CF" isDefault="false" mode="Opaque" backcolor="#EDEDED" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<field name="id" class="java.lang.Long"/>
+		<field name="name" class="java.lang.String"/>
+		<field name="immediateCalloutCount" class="java.lang.Integer"/>
+		<field name="downTime" class="java.lang.Integer"/>
+		<field name="tasks" class="java.lang.String"/>
+		<variable name="immediateCalloutSum" class="java.lang.Integer" calculation="Sum">
+			<variableExpression><![CDATA[$F{immediateCalloutCount}]]></variableExpression>
+		</variable>
+		<variable name="downTimeSum" class="java.lang.Integer" calculation="Sum">
+			<variableExpression><![CDATA[$F{downTime}]]></variableExpression>
+		</variable>
+		<group name="assetName">
+			<groupExpression><![CDATA[$F{name}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="taskList" class="java.util.List"/>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="totalAssetsOnTasksCount" class="java.lang.String"/>
+	<field name="assetList" class="java.util.List"/>
+	<field name="totalDownTime" class="java.util.LinkedHashMap"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="121" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="0" y="57" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="87" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{startDateString}+" to "+$P{endDateString}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="394" splitType="Stretch">
+			<bar3DChart>
+				<chart>
+					<reportElement x="0" y="0" width="782" height="394"/>
+					<chartTitle position="Bottom">
+						<font isUnderline="false"/>
+						<titleExpression><![CDATA["Total: "+$F{totalAssetsOnTasksCount}]]></titleExpression>
+					</chartTitle>
+					<chartSubtitle/>
+					<chartLegend/>
+				</chart>
+				<categoryDataset>
+					<dataset>
+						<datasetRun subDataset="dataset1">
+							<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{assetList})]]></dataSourceExpression>
+						</datasetRun>
+					</dataset>
+					<categorySeries>
+						<seriesExpression><![CDATA["Immediate Callouts"]]></seriesExpression>
+						<categoryExpression><![CDATA[$F{name}]]></categoryExpression>
+						<valueExpression><![CDATA[$F{immediateCalloutCount}]]></valueExpression>
+					</categorySeries>
+				</categoryDataset>
+				<bar3DPlot isShowLabels="true">
+					<plot labelRotation="-60.0"/>
+					<itemLabel color="#000000" backgroundColor="#FFFFFF"/>
+					<categoryAxisFormat labelRotation="-60.0">
+						<axisFormat>
+							<labelFont/>
+							<tickLabelFont/>
+						</axisFormat>
+					</categoryAxisFormat>
+					<valueAxisFormat>
+						<axisFormat>
+							<labelFont/>
+							<tickLabelFont/>
+						</axisFormat>
+					</valueAxisFormat>
+				</bar3DPlot>
+			</bar3DChart>
+		</band>
+		<band height="394">
+			<bar3DChart>
+				<chart>
+					<reportElement x="0" y="0" width="782" height="394"/>
+					<chartTitle position="Bottom">
+						<font isBold="false" isUnderline="false"/>
+						<titleExpression><![CDATA["Total: "+$F{totalDownTime}.total+"min"+" ("+$F{totalDownTime}.hours+"h:"+$F{totalDownTime}.minutes+"m)"]]></titleExpression>
+					</chartTitle>
+					<chartSubtitle/>
+					<chartLegend position="Bottom">
+						<font isUnderline="true"/>
+					</chartLegend>
+				</chart>
+				<categoryDataset>
+					<dataset>
+						<datasetRun subDataset="dataset1">
+							<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{assetList})]]></dataSourceExpression>
+						</datasetRun>
+					</dataset>
+					<categorySeries>
+						<seriesExpression><![CDATA["Down Time (min)"]]></seriesExpression>
+						<categoryExpression><![CDATA[$F{name}]]></categoryExpression>
+						<valueExpression><![CDATA[$F{downTime}]]></valueExpression>
+					</categorySeries>
+				</categoryDataset>
+				<bar3DPlot isShowLabels="true">
+					<plot labelRotation="-60.0">
+						<seriesColor seriesOrder="0" color="#FF9900"/>
+					</plot>
+					<itemLabel color="#000000" backgroundColor="#FFFFFF"/>
+					<categoryAxisFormat labelRotation="-60.0">
+						<axisFormat>
+							<labelFont/>
+							<tickLabelFont/>
+						</axisFormat>
+					</categoryAxisFormat>
+					<valueAxisFormat>
+						<axisFormat>
+							<labelFont/>
+							<tickLabelFont/>
+						</axisFormat>
+					</valueAxisFormat>
+				</bar3DPlot>
+			</bar3DChart>
+		</band>
+		<band height="394">
+			<componentElement>
+				<reportElement key="table 1" style="table" x="0" y="0" width="782" height="394"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{assetList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="774">
+						<jr:groupHeader groupName="assetName">
+							<jr:cell height="30" rowSpan="1">
+								<textField>
+									<reportElement x="0" y="0" width="774" height="30"/>
+									<textElement verticalAlignment="Middle">
+										<font size="12" isBold="true"/>
+									</textElement>
+									<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+								</textField>
+							</jr:cell>
+						</jr:groupHeader>
+						<jr:detailCell style="table_TD" height="40" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="774" height="40"/>
+								<textElement verticalAlignment="Middle"/>
+								<textFieldExpression class="java.lang.String"><![CDATA[""+$F{tasks}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="40" splitType="Stretch">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="40">
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement key="staticText-1" x="221" y="12" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary of Calculation Method"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="50" width="782" height="311"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="782" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="782" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/inventoryValueDetailed.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/inventoryValueDetailed.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/inventoryValueDetailed.jrxml	(revision 875)
@@ -0,0 +1,504 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="782" leftMargin="30" rightMargin="30" topMargin="12" bottomMargin="12" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="0"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<style name="table" isDefault="false" fill="Solid" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="0.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#C7C7C7" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="10" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+		<conditionalStyle>
+			<conditionExpression><![CDATA[new Boolean($V{REPORT_COUNT}.intValue()%2==0)]]></conditionExpression>
+			<style isDefault="false" style="table_TD" backcolor="#F7F7F7"/>
+		</conditionalStyle>
+	</style>
+	<style name="table_CF" isDefault="false" mode="Opaque" backcolor="#EDEDED" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="horizontalBorder" isDefault="false">
+		<box>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.5"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<field name="name" class="java.lang.String"/>
+		<field name="unitsInStock" class="java.lang.Integer"/>
+		<field name="inventoryLocation" class="java.lang.Object"/>
+		<field name="unitOfMeasure" class="java.lang.Object"/>
+		<field name="description" class="java.lang.String"/>
+		<field name="estimatedUnitPriceAmount" class="java.math.BigDecimal"/>
+		<field name="estimatedUnitPriceCurrency" class="java.lang.String"/>
+		<variable name="totalValue" class="java.math.BigDecimal" calculation="Sum">
+			<variableExpression><![CDATA[$F{estimatedUnitPriceAmount}]]></variableExpression>
+		</variable>
+	</subDataset>
+	<subDataset name="dataset2_inventoryTypes">
+		<field name="name" class="java.lang.String"/>
+	</subDataset>
+	<subDataset name="dataset3_inventoryGroups">
+		<field name="name" class="java.lang.String"/>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="inventoryItemList" class="java.util.List"/>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="inventoryItemCount" class="java.lang.Integer"/>
+	<field name="errorMessage" class="java.lang.String"/>
+	<field name="inventoryItemTotalValue" class="java.math.BigDecimal"/>
+	<field name="currency" class="java.lang.String"/>
+	<field name="inventoryTypes" class="java.util.List"/>
+	<field name="site" class="java.lang.Object"/>
+	<field name="inventoryGroups" class="java.util.List"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="54" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" mode="Transparent" x="400" y="6" width="350" height="20" backcolor="#FFFFFF"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="50"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField>
+				<reportElement x="400" y="26" width="350" height="18"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$F{site}.name]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="438" splitType="Stretch">
+			<textField isStretchWithOverflow="true" isBlankWhenNull="true">
+				<reportElement x="0" y="27" width="105" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Value("+$F{currency}+"): "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="# ##0" isBlankWhenNull="true">
+				<reportElement x="105" y="44" width="235" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.Integer"><![CDATA[$F{inventoryItemCount}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="#,##0.00" isBlankWhenNull="true">
+				<reportElement x="105" y="27" width="235" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{inventoryItemTotalValue}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" isBlankWhenNull="true">
+				<reportElement x="0" y="44" width="105" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Inventory Items: "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement x="0" y="105" width="340" height="31"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement mode="Opaque" x="0" y="72" width="340" height="29" forecolor="#FF0000" backcolor="#FFCCCC">
+					<printWhenExpression><![CDATA[$F{errorMessage} != null ? true:false]]></printWhenExpression>
+				</reportElement>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{errorMessage}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement style="horizontalBorder" x="175" y="173" width="160" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Inventory Types"]]></textFieldExpression>
+			</textField>
+			<componentElement>
+				<reportElement stretchType="RelativeToTallestObject" x="175" y="190" width="160" height="17" isPrintWhenDetailOverflows="true"/>
+				<jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
+					<datasetRun subDataset="dataset2_inventoryTypes">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{inventoryTypes})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:listContents height="17" width="160">
+						<textField>
+							<reportElement style="horizontalBorder" x="0" y="0" width="160" height="17"/>
+							<textElement verticalAlignment="Middle">
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+						</textField>
+					</jr:listContents>
+				</jr:list>
+			</componentElement>
+			<textField>
+				<reportElement style="horizontalBorder" x="0" y="173" width="160" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Inventory Groups"]]></textFieldExpression>
+			</textField>
+			<componentElement>
+				<reportElement stretchType="RelativeToTallestObject" x="0" y="190" width="160" height="17" isPrintWhenDetailOverflows="true"/>
+				<jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
+					<datasetRun subDataset="dataset3_inventoryGroups">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{inventoryGroups})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:listContents height="17" width="160">
+						<textField>
+							<reportElement style="horizontalBorder" x="0" y="0" width="160" height="17"/>
+							<textElement verticalAlignment="Middle">
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+						</textField>
+					</jr:listContents>
+				</jr:list>
+			</componentElement>
+			<textField isStretchWithOverflow="true">
+				<reportElement x="0" y="147" width="335" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isUnderline="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Included:"]]></textFieldExpression>
+			</textField>
+		</band>
+		<band height="489">
+			<componentElement>
+				<reportElement key="table 1" x="0" y="0" width="782" height="438"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{inventoryItemList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="127">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="117" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Inventory Item"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="24" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="2" width="117" height="20"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="237">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="237" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Description"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="24" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="237" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="90">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="90" height="20"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="true"/>
+								</textElement>
+								<text><![CDATA[Location]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="24" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="90" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{inventoryLocation}.name+ " in "+$F{inventoryLocation}.inventoryStore.name]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="104">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="104" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["In Stock"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="24" rowSpan="1">
+							<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+								<leftPen lineWidth="0.0"/>
+								<rightPen lineWidth="0.0"/>
+							</box>
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="104" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{unitsInStock}+" "+$F{unitOfMeasure}.name]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="90">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="90" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Unit Price"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="24" rowSpan="1">
+							<textField isStretchWithOverflow="true" pattern="# ##0.00">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="90" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{estimatedUnitPriceAmount}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="82">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="82" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Total"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="24" rowSpan="1">
+							<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+								<leftPen lineWidth="0.0"/>
+								<rightPen lineWidth="0.0"/>
+							</box>
+							<textField isStretchWithOverflow="true" pattern="# ##0.00">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="82" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{estimatedUnitPriceAmount}.multiply( $F{unitsInStock} )]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="52">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="51" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Currency"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="24" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="2" width="51" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{estimatedUnitPriceCurrency}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="782" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="782" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/inventoryValueOverview.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/inventoryValueOverview.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/inventoryValueOverview.jrxml	(revision 875)
@@ -0,0 +1,399 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="782" leftMargin="30" rightMargin="30" topMargin="12" bottomMargin="12" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="0"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<style name="table" isDefault="false" fill="Solid" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="0.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#C7C7C7" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="10" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+		<conditionalStyle>
+			<conditionExpression><![CDATA[new Boolean($V{REPORT_COUNT}.intValue()%2==0)]]></conditionExpression>
+			<style isDefault="false" style="table_TD" backcolor="#F7F7F7"/>
+		</conditionalStyle>
+	</style>
+	<style name="table_CF" isDefault="false" mode="Opaque" backcolor="#EDEDED" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="horizontalBorder" isDefault="false">
+		<box>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.5"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<subDataset name="dataset2_inventoryTypes">
+		<field name="name" class="java.lang.String"/>
+		<field name="value" class="java.math.BigDecimal"/>
+	</subDataset>
+	<subDataset name="dataset3_inventoryGroups">
+		<field name="name" class="java.lang.String"/>
+		<field name="value" class="java.math.BigDecimal"/>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="inventoryItemCount" class="java.lang.Integer"/>
+	<field name="errorMessage" class="java.lang.String"/>
+	<field name="inventoryItemTotalValue" class="java.math.BigDecimal"/>
+	<field name="currency" class="java.lang.String"/>
+	<field name="inventoryTypes" class="java.util.List"/>
+	<field name="inventoryGroups" class="java.util.List"/>
+	<field name="site" class="java.lang.Object"/>
+	<field name="groups" class="java.util.List"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="54" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" mode="Transparent" x="400" y="6" width="350" height="20" backcolor="#FFFFFF"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="50"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField>
+				<reportElement x="400" y="26" width="350" height="18"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$F{site}.name]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="438" splitType="Stretch">
+			<textField isStretchWithOverflow="true" isBlankWhenNull="true">
+				<reportElement x="0" y="27" width="105" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Value("+$F{currency}+"): "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="# ##0" isBlankWhenNull="true">
+				<reportElement x="105" y="44" width="235" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.Integer"><![CDATA[$F{inventoryItemCount}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="#,##0.00" isBlankWhenNull="true">
+				<reportElement x="105" y="27" width="235" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{inventoryItemTotalValue}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" isBlankWhenNull="true">
+				<reportElement x="0" y="44" width="105" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Inventory Items: "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement x="0" y="105" width="340" height="31"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement mode="Opaque" x="0" y="72" width="340" height="29" forecolor="#FF0000" backcolor="#FFCCCC">
+					<printWhenExpression><![CDATA[$F{errorMessage} != null ? true:false]]></printWhenExpression>
+				</reportElement>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{errorMessage}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement style="horizontalBorder" x="400" y="148" width="335" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Inventory Types"]]></textFieldExpression>
+			</textField>
+			<componentElement>
+				<reportElement stretchType="RelativeToTallestObject" x="400" y="199" width="335" height="17" isPrintWhenDetailOverflows="true"/>
+				<jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
+					<datasetRun subDataset="dataset2_inventoryTypes">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{inventoryTypes})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:listContents height="17" width="335">
+						<textField>
+							<reportElement style="horizontalBorder" x="0" y="0" width="235" height="17"/>
+							<textElement verticalAlignment="Middle">
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+						</textField>
+						<textField pattern="#,##0.00">
+							<reportElement style="horizontalBorder" x="235" y="0" width="100" height="17"/>
+							<textElement verticalAlignment="Middle">
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{value}]]></textFieldExpression>
+						</textField>
+					</jr:listContents>
+				</jr:list>
+			</componentElement>
+			<textField>
+				<reportElement style="horizontalBorder" x="0" y="148" width="335" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Inventory Groups"]]></textFieldExpression>
+			</textField>
+			<componentElement>
+				<reportElement stretchType="RelativeToTallestObject" x="0" y="199" width="335" height="17" isPrintWhenDetailOverflows="true"/>
+				<jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
+					<datasetRun subDataset="dataset3_inventoryGroups">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{inventoryGroups})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:listContents height="17" width="335">
+						<textField>
+							<reportElement style="horizontalBorder" x="0" y="0" width="235" height="17"/>
+							<textElement verticalAlignment="Middle">
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+						</textField>
+						<textField pattern="#,##0.00">
+							<reportElement style="horizontalBorder" x="235" y="0" width="100" height="17"/>
+							<textElement verticalAlignment="Middle">
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{value}]]></textFieldExpression>
+						</textField>
+					</jr:listContents>
+				</jr:list>
+			</componentElement>
+			<textField>
+				<reportElement style="horizontalBorder" x="0" y="165" width="235" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Name"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement style="horizontalBorder" x="235" y="165" width="100" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Value("+$F{currency}+")"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement style="horizontalBorder" x="635" y="165" width="100" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Value("+$F{currency}+")"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement style="horizontalBorder" x="400" y="165" width="235" height="17"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Name"]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" isBlankWhenNull="true">
+				<reportElement style="horizontalBorder" x="0" y="182" width="235" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="10" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Value:"]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="#,##0.00" isBlankWhenNull="true">
+				<reportElement style="horizontalBorder" x="235" y="182" width="100" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="10" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{inventoryItemTotalValue}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" isBlankWhenNull="true">
+				<reportElement style="horizontalBorder" x="400" y="182" width="235" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="10" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Value:"]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="#,##0.00" isBlankWhenNull="true">
+				<reportElement style="horizontalBorder" x="635" y="182" width="100" height="17" isPrintWhenDetailOverflows="true"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="10" isBold="false"/>
+				</textElement>
+				<textFieldExpression class="java.math.BigDecimal"><![CDATA[$F{inventoryItemTotalValue}]]></textFieldExpression>
+			</textField>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="782" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="782" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/mandatoryRequirements.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/mandatoryRequirements.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/mandatoryRequirements.jrxml	(revision 875)
@@ -0,0 +1,335 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="824" leftMargin="9" rightMargin="9" topMargin="9" bottomMargin="9" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.5"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="665"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="table" isDefault="false">
+		<pen lineWidth="0.5"/>
+		<box>
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="1.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="1.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#F0F8FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#BFE1FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" pattern="">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_GH" isDefault="false" mode="Opaque" backcolor="#D2EFF7"/>
+	<subDataset name="dataset1">
+		<queryString language="SQL">
+			<![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]>
+		</queryString>
+		<field name="assetDescription" class="java.lang.String"/>
+		<field name="taskDescription" class="java.lang.String"/>
+		<field name="assetName" class="java.lang.String"/>
+		<field name="completionFigures" class="java.lang.String"/>
+		<field name="taskId" class="java.lang.String"/>
+		<group name="group1">
+			<groupExpression><![CDATA[$F{assetName}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="dataList" class="java.util.List"/>
+	<field name="site" class="java.lang.Object"/>
+	<field name="section" class="java.lang.Object"/>
+	<field name="summary" class="java.lang.String"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="57" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="398" y="5" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField>
+				<reportElement x="398" y="25" width="340" height="15" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Center">
+					<font fontName="Serif" size="10"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$F{site}.name+", "+"Section: "+$F{section}.name]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="398" y="40" width="340" height="12"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{startDateString}+" to "+$P{endDateString}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="492" splitType="Immediate">
+			<printWhenExpression><![CDATA[!$F{dataList}.isEmpty()]]></printWhenExpression>
+			<componentElement>
+				<reportElement key="table" style="table" x="2" y="2" width="820" height="488"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="100" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Asset]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="96" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{assetName}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="100" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<text><![CDATA[Description]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="96" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{assetDescription}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="441">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="435" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Mandatory Requirement (Recurring Task)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="435" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Task #"+$F{taskId}+" - "+$F{taskDescription}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="112">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="2" y="0" width="108" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<text><![CDATA[Complete (Sub Tasks)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="108" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{completionFigures}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+		<band height="85">
+			<printWhenExpression><![CDATA[$F{dataList}.isEmpty()]]></printWhenExpression>
+			<staticText>
+				<reportElement x="0" y="35" width="824" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<text><![CDATA[No mandatory requirements found for this section.]]></text>
+			</staticText>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Prevent">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement key="staticText-1" x="242" y="0" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="2" y="63" width="555" height="48"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summary}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="824" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="824" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="18"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/reactiveRatio.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/reactiveRatio.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/reactiveRatio.jrxml	(revision 875)
@@ -0,0 +1,809 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="782" leftMargin="30" rightMargin="30" topMargin="20" bottomMargin="20" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="2.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="170"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="table" isDefault="false">
+		<box>
+			<pen lineWidth="1.0" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#F0F8FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#BFE1FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table 1" isDefault="false">
+		<box>
+			<pen lineWidth="1.0" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table 1_TH" isDefault="false" mode="Opaque" backcolor="#F0F8FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table 1_CH" isDefault="false" mode="Opaque" backcolor="#BFE1FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table 1_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<field name="immediateCalloutPercentage" class="java.math.BigDecimal"/>
+	<field name="totalPreventativePercentage" class="java.math.BigDecimal"/>
+	<field name="immediateCalloutCount" class="java.lang.Integer"/>
+	<field name="totalAssetsOnTasksCount" class="java.lang.Integer"/>
+	<field name="totalPreventativeCount" class="java.lang.Integer"/>
+	<field name="unscheduledBreakinCount" class="java.lang.Integer"/>
+	<field name="preventativeMaintenanceCount" class="java.lang.Integer"/>
+	<field name="taskQuery" class="java.lang.String"/>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="immediateCalloutWorkDone" class="java.util.LinkedHashMap"/>
+	<field name="totalPreventativeWorkDone" class="java.util.LinkedHashMap"/>
+	<field name="unscheduledBreakinWorkDone" class="java.util.LinkedHashMap"/>
+	<field name="preventativeMaintenanceWorkDone" class="java.util.LinkedHashMap"/>
+	<field name="totalWorkDone" class="java.util.LinkedHashMap"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="121" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="0" y="57" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="87" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{startDateString}+" to "+$P{endDateString}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="394" splitType="Stretch">
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="40" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Immediate Callout: "]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="60" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Preventative: "]]></textFieldExpression>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="40" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{immediateCalloutPercentage}.setScale(2, RoundingMode.HALF_UP)]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="60" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalPreventativePercentage}.setScale(2, RoundingMode.HALF_UP)]]></textFieldExpression>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="0" y="80" width="157" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total: "]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="80" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<line>
+				<reportElement x="0" y="100" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<line>
+				<reportElement x="0" y="79" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<line>
+				<reportElement x="0" y="60" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<line>
+				<reportElement x="0" y="39" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="20" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none"/>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="20" width="79" height="20"/>
+				<textElement verticalAlignment="Middle"/>
+			</textField>
+			<line>
+				<reportElement x="0" y="20" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<pie3DChart>
+				<chart theme="default">
+					<reportElement x="426" y="0" width="356" height="197"/>
+					<chartTitle/>
+					<chartSubtitle/>
+					<chartLegend/>
+				</chart>
+				<pieDataset>
+					<pieSeries>
+						<keyExpression><![CDATA["Immediate"]]></keyExpression>
+						<valueExpression><![CDATA[$F{immediateCalloutPercentage}]]></valueExpression>
+						<labelExpression><![CDATA[$F{immediateCalloutPercentage}.setScale(2, RoundingMode.HALF_UP)]]></labelExpression>
+					</pieSeries>
+					<pieSeries>
+						<keyExpression><![CDATA["Preventative"]]></keyExpression>
+						<valueExpression><![CDATA[$F{totalPreventativePercentage}]]></valueExpression>
+						<labelExpression><![CDATA[$F{totalPreventativePercentage}.setScale(2, RoundingMode.HALF_UP)]]></labelExpression>
+					</pieSeries>
+				</pieDataset>
+				<pie3DPlot depthFactor="0.1" isCircular="false">
+					<plot>
+						<seriesColor seriesOrder="0" color="#FF0000"/>
+						<seriesColor seriesOrder="1" color="#00CC00"/>
+						<seriesColor seriesOrder="2" color="#FF9900"/>
+					</plot>
+					<itemLabel color="#000000" backgroundColor="#FFFFFF"/>
+				</pie3DPlot>
+			</pie3DChart>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="257" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle"/>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{preventativeMaintenanceCount}]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="277" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalPreventativeCount}]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="277" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<line>
+				<reportElement x="0" y="297" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="257" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Preventative Maintenance: "]]></textFieldExpression>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="237" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="217" width="130" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<line>
+				<reportElement x="0" y="257" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="197" width="130" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Count (Assets on Tasks)"]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="237" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Unscheduled Breakin: "]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="276" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<pie3DChart>
+				<chart>
+					<reportElement x="426" y="197" width="356" height="197"/>
+					<chartTitle/>
+					<chartSubtitle/>
+					<chartLegend/>
+				</chart>
+				<pieDataset>
+					<pieSeries>
+						<keyExpression><![CDATA["Immediate"]]></keyExpression>
+						<valueExpression><![CDATA[$F{immediateCalloutCount}]]></valueExpression>
+						<labelExpression><![CDATA[$F{immediateCalloutCount}]]></labelExpression>
+					</pieSeries>
+					<pieSeries>
+						<keyExpression><![CDATA["Preventative Maintenance"]]></keyExpression>
+						<valueExpression><![CDATA[$F{preventativeMaintenanceCount}]]></valueExpression>
+						<labelExpression><![CDATA[$F{preventativeMaintenanceCount}]]></labelExpression>
+					</pieSeries>
+					<pieSeries>
+						<keyExpression><![CDATA["Unscheduled Breakin"]]></keyExpression>
+						<valueExpression><![CDATA[$F{unscheduledBreakinCount}]]></valueExpression>
+						<labelExpression><![CDATA[$F{unscheduledBreakinCount}]]></labelExpression>
+					</pieSeries>
+				</pieDataset>
+				<pie3DPlot depthFactor="0.1" isCircular="false">
+					<plot>
+						<seriesColor seriesOrder="0" color="#FF0000"/>
+						<seriesColor seriesOrder="1" color="#00CC00"/>
+						<seriesColor seriesOrder="2" color="#FF9900"/>
+					</plot>
+					<itemLabel color="#000000" backgroundColor="#FFFFFF"/>
+				</pie3DPlot>
+			</pie3DChart>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="217" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="237" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{unscheduledBreakinCount}]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="217" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="217" width="79" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<line>
+				<reportElement x="0" y="236" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="257" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="197" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Description"]]></textFieldExpression>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="197" width="79" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="0" y="277" width="157" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Preventative: "]]></textFieldExpression>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="0" width="79" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Percentage (%)"]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="0" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Description"]]></textFieldExpression>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="40" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{immediateCalloutCount}]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="60" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalPreventativeCount}]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="80" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalAssetsOnTasksCount}]]></textFieldExpression>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="20" width="130" height="20"/>
+				<textElement verticalAlignment="Middle"/>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="0" width="130" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Count (Assets on Tasks)"]]></textFieldExpression>
+			</textField>
+		</band>
+		<band height="394">
+			<pie3DChart>
+				<chart>
+					<reportElement x="426" y="0" width="356" height="197"/>
+					<chartTitle/>
+					<chartSubtitle/>
+					<chartLegend/>
+				</chart>
+				<pieDataset>
+					<pieSeries>
+						<keyExpression><![CDATA["Immediate"]]></keyExpression>
+						<valueExpression><![CDATA[$F{immediateCalloutWorkDone}.percentage]]></valueExpression>
+						<labelExpression><![CDATA[$F{immediateCalloutWorkDone}.percentage.setScale(2, RoundingMode.HALF_UP)]]></labelExpression>
+					</pieSeries>
+					<pieSeries>
+						<keyExpression><![CDATA["Total Preventative"]]></keyExpression>
+						<valueExpression><![CDATA[$F{totalPreventativeWorkDone}.percentage]]></valueExpression>
+						<labelExpression><![CDATA[$F{totalPreventativeWorkDone}.percentage.setScale(2, RoundingMode.HALF_UP)]]></labelExpression>
+					</pieSeries>
+				</pieDataset>
+				<pie3DPlot depthFactor="0.1" isCircular="false">
+					<plot>
+						<seriesColor seriesOrder="0" color="#FF0000"/>
+						<seriesColor seriesOrder="1" color="#00CC00"/>
+						<seriesColor seriesOrder="2" color="#FF9900"/>
+					</plot>
+					<itemLabel color="#000000" backgroundColor="#FFFFFF"/>
+				</pie3DPlot>
+			</pie3DChart>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="0" width="79" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Percentage (%)"]]></textFieldExpression>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="20" width="130" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="0" width="130" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Work Done (hh:mm)"]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="100" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<line>
+				<reportElement x="0" y="20" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="40" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{immediateCalloutWorkDone}.percentage.setScale(2, RoundingMode.HALF_UP)]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="60" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalPreventativeWorkDone}.percentage.setScale(2, RoundingMode.HALF_UP)]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="20" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="80" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<line>
+				<reportElement x="0" y="60" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="60" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalPreventativeWorkDone}.hours+":"+$F{totalPreventativeWorkDone}.minutes]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="80" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalWorkDone}.hours+":"+$F{totalWorkDone}.minutes]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="0" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Description"]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="79" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="40" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Immediate Callout: "]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="60" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Preventative: "]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="39" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="20" width="79" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="0" y="80" width="157" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total: "]]></textFieldExpression>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="236" y="40" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{immediateCalloutWorkDone}.hours+":"+$F{immediateCalloutWorkDone}.minutes]]></textFieldExpression>
+			</textField>
+			<pie3DChart>
+				<chart>
+					<reportElement x="426" y="197" width="356" height="197"/>
+					<chartTitle/>
+					<chartSubtitle/>
+					<chartLegend/>
+				</chart>
+				<pieDataset>
+					<pieSeries>
+						<keyExpression><![CDATA["Immediate"]]></keyExpression>
+						<valueExpression><![CDATA[$F{immediateCalloutWorkDone}.total]]></valueExpression>
+						<labelExpression><![CDATA[$F{immediateCalloutWorkDone}.hours+":"+$F{immediateCalloutWorkDone}.minutes]]></labelExpression>
+					</pieSeries>
+					<pieSeries>
+						<keyExpression><![CDATA["Preventative Maintenance"]]></keyExpression>
+						<valueExpression><![CDATA[$F{preventativeMaintenanceWorkDone}.total]]></valueExpression>
+						<labelExpression><![CDATA[$F{preventativeMaintenanceWorkDone}.hours+":"+$F{preventativeMaintenanceWorkDone}.minutes]]></labelExpression>
+					</pieSeries>
+					<pieSeries>
+						<keyExpression><![CDATA["Unscheduled Breakin"]]></keyExpression>
+						<valueExpression><![CDATA[$F{unscheduledBreakinWorkDone}.total]]></valueExpression>
+						<labelExpression><![CDATA[$F{unscheduledBreakinWorkDone}.hours+":"+$F{unscheduledBreakinWorkDone}.minutes]]></labelExpression>
+					</pieSeries>
+				</pieDataset>
+				<pie3DPlot depthFactor="0.1" isCircular="false">
+					<plot>
+						<seriesColor seriesOrder="0" color="#FF0000"/>
+						<seriesColor seriesOrder="1" color="#00CC00"/>
+						<seriesColor seriesOrder="2" color="#FF9900"/>
+					</plot>
+					<itemLabel color="#000000" backgroundColor="#FFFFFF"/>
+				</pie3DPlot>
+			</pie3DChart>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="197" width="79" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="197" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Description"]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="276" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="217" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="257" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="197" width="130" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Work Done (hh:mm)"]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="157" y="277" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="237" width="79" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField pattern="#,##0.00 %" isBlankWhenNull="true">
+				<reportElement x="157" y="217" width="79" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<line>
+				<reportElement x="0" y="257" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<line>
+				<reportElement x="0" y="297" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="0" y="277" width="157" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Preventative: "]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="277" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{totalPreventativeWorkDone}.hours+":"+$F{totalPreventativeWorkDone}.minutes]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="236" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="217" width="130" height="20"/>
+				<textElement verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="237" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Unscheduled Breakin: "]]></textFieldExpression>
+			</textField>
+			<textField isBlankWhenNull="true">
+				<reportElement x="0" y="257" width="157" height="20"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Preventative Maintenance: "]]></textFieldExpression>
+			</textField>
+			<line>
+				<reportElement x="0" y="217" width="366" height="1" forecolor="#999999"/>
+			</line>
+			<textField isBlankWhenNull="true">
+				<reportElement x="236" y="257" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{preventativeMaintenanceWorkDone}.hours+":"+$F{preventativeMaintenanceWorkDone}.minutes]]></textFieldExpression>
+			</textField>
+			<textField pattern="###0.00" isBlankWhenNull="true">
+				<reportElement x="236" y="237" width="130" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{unscheduledBreakinWorkDone}.hours+":"+$F{unscheduledBreakinWorkDone}.minutes]]></textFieldExpression>
+			</textField>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="40" splitType="Stretch">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="40">
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="277">
+			<textField>
+				<reportElement key="staticText-1" x="221" y="0" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary of Calculation Method"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="30" width="782" height="245"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="782" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="782" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/regulatoryRequirements.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/regulatoryRequirements.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/regulatoryRequirements.jrxml	(revision 875)
@@ -0,0 +1,335 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="824" leftMargin="9" rightMargin="9" topMargin="9" bottomMargin="9" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.5"/>
+	<property name="ireport.x" value="22"/>
+	<property name="ireport.y" value="480"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="table" isDefault="false">
+		<pen lineWidth="0.5"/>
+		<box>
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="1.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="1.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#F0F8FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#BFE1FF">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" pattern="">
+		<box>
+			<pen lineWidth="0.5" lineColor="#000000"/>
+		</box>
+	</style>
+	<style name="table_GH" isDefault="false" mode="Opaque" backcolor="#D2EFF7"/>
+	<subDataset name="dataset1">
+		<queryString language="SQL">
+			<![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]>
+		</queryString>
+		<field name="assetDescription" class="java.lang.String"/>
+		<field name="taskDescription" class="java.lang.String"/>
+		<field name="assetName" class="java.lang.String"/>
+		<field name="completionFigures" class="java.lang.String"/>
+		<field name="taskId" class="java.lang.String"/>
+		<group name="group1">
+			<groupExpression><![CDATA[$F{assetName}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="dataList" class="java.util.List"/>
+	<field name="site" class="java.lang.Object"/>
+	<field name="section" class="java.lang.Object"/>
+	<field name="summary" class="java.lang.String"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="57" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="398" y="5" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="14"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField>
+				<reportElement x="398" y="25" width="340" height="15" isPrintWhenDetailOverflows="true"/>
+				<textElement textAlignment="Center">
+					<font fontName="Serif" size="10"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Site: "+$F{site}.name+", "+"Section: "+$F{section}.name]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="398" y="40" width="340" height="12"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{startDateString}+" to "+$P{endDateString}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="492" splitType="Immediate">
+			<printWhenExpression><![CDATA[!$F{dataList}.isEmpty()]]></printWhenExpression>
+			<componentElement>
+				<reportElement key="table" style="table" x="2" y="2" width="820" height="488"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="0" y="0" width="100" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Asset]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="96" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{assetName}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="100">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="0" y="0" width="100" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<text><![CDATA[Description]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="96" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{assetDescription}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="441">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement stretchType="RelativeToTallestObject" x="2" y="0" width="435" height="32" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="10" isBold="false"/>
+								</textElement>
+								<text><![CDATA[Regulatory Requirement (Recurring Task)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="435" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Task #"+$F{taskId}+" - "+$F{taskDescription}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="112">
+						<jr:columnHeader style="table_CH" height="32" rowSpan="1">
+							<staticText>
+								<reportElement x="2" y="0" width="108" height="32"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<text><![CDATA[Complete (Sub Tasks)]]></text>
+							</staticText>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement stretchType="RelativeToTallestObject" mode="Transparent" x="2" y="0" width="108" height="20" isPrintWhenDetailOverflows="true"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="8"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{completionFigures}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+		<band height="85">
+			<printWhenExpression><![CDATA[$F{dataList}.isEmpty()]]></printWhenExpression>
+			<staticText>
+				<reportElement x="0" y="35" width="824" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<text><![CDATA[No regulatory requirements found for this section.]]></text>
+			</staticText>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="28" splitType="Prevent">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="28">
+			<textField evaluationTime="Report">
+				<reportElement x="784" y="14" width="40" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="50" y="2" width="200" height="12"/>
+				<textElement>
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="2" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="14" width="50" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="50" y="14" width="200" height="12"/>
+				<textElement markup="none">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="704" y="14" width="80" height="12"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif" size="8"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement key="staticText-1" x="242" y="0" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="2" y="63" width="555" height="48"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summary}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="824" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="824" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="18"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/stockTakeByLocation.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/stockTakeByLocation.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/stockTakeByLocation.jrxml	(revision 875)
@@ -0,0 +1,421 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="782" leftMargin="30" rightMargin="30" topMargin="12" bottomMargin="12" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="309"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<style name="table" isDefault="false" fill="Solid" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="0.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#C7C7C7" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="10" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+		<conditionalStyle>
+			<conditionExpression><![CDATA[new Boolean($V{REPORT_COUNT}.intValue()%2==0)]]></conditionExpression>
+			<style isDefault="false" style="table_TD" backcolor="#F7F7F7"/>
+		</conditionalStyle>
+	</style>
+	<style name="table_CF" isDefault="false" mode="Opaque" backcolor="#EDEDED" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<field name="name" class="java.lang.String"/>
+		<field name="unitsInStock" class="java.lang.Integer"/>
+		<field name="inventoryLocation" class="java.lang.Object"/>
+		<field name="picture" class="java.lang.Object"/>
+		<field name="unitOfMeasure" class="java.lang.Object"/>
+		<field name="description" class="java.lang.String"/>
+		<group name="group1">
+			<groupExpression><![CDATA[$F{inventoryLocation}.name]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="locationString" class="java.lang.String"/>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="inventoryItemList" class="java.util.List"/>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="inventoryItemCount" class="java.lang.Integer"/>
+	<field name="locations" class="java.lang.String"/>
+	<field name="errorMessage" class="java.lang.String"/>
+	<field name="locationCount" class="java.lang.Integer"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="93" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" mode="Transparent" x="0" y="50" width="340" height="26" backcolor="#FFFFFF"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="50"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="76" width="340" height="17"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total - Items: "+$F{inventoryItemCount}+", Locations: "+$F{locationCount}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement mode="Opaque" x="400" y="4" width="382" height="46" isPrintWhenDetailOverflows="true" forecolor="#FF0000" backcolor="#FFCCCC">
+					<printWhenExpression><![CDATA[$F{errorMessage} != null ? true:false]]></printWhenExpression>
+				</reportElement>
+				<textElement textAlignment="Center" verticalAlignment="Middle">
+					<font fontName="Serif" size="12" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{errorMessage}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="438" splitType="Stretch">
+			<componentElement>
+				<reportElement key="table 1" x="0" y="0" width="782" height="438"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{inventoryItemList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="127">
+						<jr:groupHeader groupName="group1">
+							<jr:cell height="20" rowSpan="1">
+								<textField isStretchWithOverflow="true">
+									<reportElement x="0" y="0" width="117" height="20"/>
+									<textElement verticalAlignment="Middle">
+										<font fontName="Serif" size="12" isBold="true"/>
+									</textElement>
+									<textFieldExpression class="java.lang.String"><![CDATA[$F{inventoryLocation}.name+" in "+$F{inventoryLocation}.inventoryStore.name]]></textFieldExpression>
+								</textField>
+							</jr:cell>
+						</jr:groupHeader>
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="117" height="20"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{inventoryLocation}.name]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="51" rowSpan="1">
+							<image hAlign="Center" vAlign="Middle">
+								<reportElement x="29" y="0" width="88" height="51"/>
+								<imageExpression class="java.awt.Image"><![CDATA[net.sf.jasperreports.engine.util.JRImageLoader.loadImage($F{picture}.images.first().data)]]></imageExpression>
+							</image>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="237">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="237" height="20"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Inventory Item"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="51" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="237" height="25"/>
+								<textElement verticalAlignment="Top">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
+							</textField>
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="25" width="237" height="25"/>
+								<textElement>
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="104">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="104" height="20"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["In Stock"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="51" rowSpan="1">
+							<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+								<leftPen lineWidth="0.0"/>
+								<rightPen lineWidth="0.0"/>
+							</box>
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="104" height="51"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{unitsInStock}+" "+$F{unitOfMeasure}.name]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="90">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="90" height="20"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Actual Stock"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="51" rowSpan="1">
+							<rectangle>
+								<reportElement x="5" y="11" width="80" height="30"/>
+							</rectangle>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="82">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="82" height="20"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Correction Required"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="51" rowSpan="1">
+							<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+								<leftPen lineWidth="0.0"/>
+								<rightPen lineWidth="0.0"/>
+							</box>
+							<rectangle radius="10">
+								<reportElement x="31" y="15" width="30" height="20"/>
+							</rectangle>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="139">
+						<jr:columnHeader style="table_CH" height="20" rowSpan="1">
+							<textField isStretchWithOverflow="true">
+								<reportElement x="0" y="0" width="139" height="20"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Notes"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="51" rowSpan="1"/>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="34" splitType="Stretch">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="17"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="14" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="14" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="17"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="17" width="200" height="17"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="17" width="82" height="17"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="34">
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="14" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="17"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="17"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="17" width="82" height="17"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="17" width="200" height="17"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="14" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement key="staticText-1" x="221" y="12" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary"]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true">
+				<reportElement x="0" y="60" width="782" height="18"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="125" width="782" height="17"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Locations found: "]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="14" y="143" width="768" height="17"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{locations}+"."]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="14" y="101" width="768" height="17"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{locationString}]]></textFieldExpression>
+			</textField>
+			<textField isStretchWithOverflow="true" pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="84" width="782" height="17"/>
+				<textElement verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Locations requested ('e.g:' is ignored, '%' is a wild card that matches zero or more characters, '_' matches any single character): "]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="782" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="782" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/stockTakeOverview.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/stockTakeOverview.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/stockTakeOverview.jrxml	(revision 875)
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="595" pageHeight="842" whenNoDataType="NoDataSection" columnWidth="535" leftMargin="30" rightMargin="30" topMargin="20" bottomMargin="20" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="240"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<style name="table" isDefault="false" fill="Solid" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="0.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#C7C7C7" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="10" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+		<conditionalStyle>
+			<conditionExpression><![CDATA[new Boolean($V{REPORT_COUNT}.intValue()%2==0)]]></conditionExpression>
+			<style isDefault="false" style="table_TD" backcolor="#F7F7F7"/>
+		</conditionalStyle>
+	</style>
+	<style name="table_CF" isDefault="false" mode="Opaque" backcolor="#EDEDED" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<field name="store" class="java.lang.String"/>
+		<field name="location" class="java.lang.String"/>
+		<group name="group1">
+			<groupExpression><![CDATA[$F{store}]]></groupExpression>
+		</group>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="inventoryLocationList" class="java.util.List"/>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="inventoryLocationCount" class="java.lang.Integer"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="121" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="0" y="57" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="87" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Total Locations: "+$F{inventoryLocationCount}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="641" splitType="Stretch">
+			<componentElement>
+				<reportElement key="table 1" x="0" y="0" width="535" height="641"/>
+				<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{inventoryLocationList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:column width="127">
+						<jr:groupHeader groupName="group1">
+							<jr:cell height="30" rowSpan="1">
+								<textField>
+									<reportElement x="0" y="0" width="127" height="30"/>
+									<textElement verticalAlignment="Middle">
+										<font fontName="Serif" size="12" isBold="true"/>
+									</textElement>
+									<textFieldExpression class="java.lang.String"><![CDATA[$F{store}]]></textFieldExpression>
+								</textField>
+							</jr:cell>
+						</jr:groupHeader>
+						<jr:columnHeader style="table_CH" height="30" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="127" height="30"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" size="12" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Store: "+$F{store}]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="30" rowSpan="1"/>
+					</jr:column>
+					<jr:column width="91">
+						<jr:columnHeader style="table_CH" height="30" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="91" height="30"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" size="12" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Location"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="30" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="91" height="30"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA[$F{location}]]></textFieldExpression>
+							</textField>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="104">
+						<jr:columnHeader style="table_CH" height="30" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="104" height="30"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="12" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Location Report Prepared"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="30" rowSpan="1">
+							<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+								<leftPen lineWidth="0.0"/>
+								<rightPen lineWidth="0.0"/>
+							</box>
+							<rectangle radius="10">
+								<reportElement x="37" y="5" width="30" height="20"/>
+							</rectangle>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="107">
+						<jr:columnHeader style="table_CH" height="30" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="107" height="30"/>
+								<textElement textAlignment="Center" verticalAlignment="Middle">
+									<font fontName="Serif" size="12" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Stock Take Complete"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="30" rowSpan="1">
+							<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+								<leftPen lineWidth="0.0"/>
+								<rightPen lineWidth="0.0"/>
+							</box>
+							<rectangle radius="10">
+								<reportElement x="38" y="5" width="30" height="20"/>
+							</rectangle>
+						</jr:detailCell>
+					</jr:column>
+					<jr:column width="107">
+						<jr:columnHeader style="table_CH" height="30" rowSpan="1">
+							<textField>
+								<reportElement x="0" y="0" width="107" height="30"/>
+								<textElement verticalAlignment="Middle">
+									<font fontName="Serif" size="12" isBold="true"/>
+								</textElement>
+								<textFieldExpression class="java.lang.String"><![CDATA["Notes"]]></textFieldExpression>
+							</textField>
+						</jr:columnHeader>
+						<jr:detailCell style="table_TD" height="30" rowSpan="1"/>
+					</jr:column>
+				</jr:table>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="40" splitType="Stretch">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="415" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="495" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="40">
+			<textField evaluationTime="Report">
+				<reportElement x="495" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="415" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement key="staticText-1" x="97" y="12" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="60" width="535" height="309"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="535" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="535" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/templateLandscape.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/templateLandscape.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/templateLandscape.jrxml	(revision 875)
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="NoDataSection" columnWidth="782" leftMargin="30" rightMargin="30" topMargin="20" bottomMargin="20" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="0"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<style name="table" isDefault="false" fill="Solid" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="0.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#C7C7C7" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="10" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+		<conditionalStyle>
+			<conditionExpression><![CDATA[new Boolean($V{REPORT_COUNT}.intValue()%2==0)]]></conditionExpression>
+			<style isDefault="false" style="table_TD" backcolor="#F7F7F7"/>
+		</conditionalStyle>
+	</style>
+	<style name="table_CF" isDefault="false" mode="Opaque" backcolor="#EDEDED" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<field name="description" class="java.lang.String"/>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="dataList" class="java.util.List"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="121" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="0" y="57" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="87" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{startDateString}+" to "+$P{endDateString}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="268" splitType="Stretch">
+			<componentElement>
+				<reportElement x="0" y="0" width="662" height="26"/>
+				<jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:listContents height="26" width="662">
+						<textField>
+							<reportElement x="0" y="0" width="400" height="20"/>
+							<textElement>
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+						</textField>
+					</jr:listContents>
+				</jr:list>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="40" splitType="Stretch">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="40">
+			<textField evaluationTime="Report">
+				<reportElement x="742" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="662" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement key="staticText-1" x="221" y="12" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary of Calculation Method"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="50" width="782" height="311"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="782" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="782" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
Index: /branches/features/grailsUpgrade/web-app/reports/templatePortrait.jrxml
===================================================================
--- /branches/features/grailsUpgrade/web-app/reports/templatePortrait.jrxml	(revision 875)
+++ /branches/features/grailsUpgrade/web-app/reports/templatePortrait.jrxml	(revision 875)
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="reportName" language="groovy" pageWidth="595" pageHeight="842" whenNoDataType="NoDataSection" columnWidth="535" leftMargin="30" rightMargin="30" topMargin="20" bottomMargin="20" isSummaryNewPage="true" isSummaryWithPageHeaderAndFooter="true">
+	<property name="ireport.scriptlethandling" value="0"/>
+	<property name="ireport.encoding" value="UTF-8"/>
+	<property name="ireport.zoom" value="1.0"/>
+	<property name="ireport.x" value="0"/>
+	<property name="ireport.y" value="166"/>
+	<import value="net.sf.jasperreports.engine.*"/>
+	<import value="java.util.*"/>
+	<import value="net.sf.jasperreports.engine.data.*"/>
+	<style name="Crosstab Data Text" isDefault="false" hAlign="Center"/>
+	<style name="table" isDefault="false" fill="Solid" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="0.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="0.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TH" isDefault="false" mode="Opaque" backcolor="#C7C7C7" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_CH" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="0.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<style name="table_TD" isDefault="false" mode="Opaque" backcolor="#FFFFFF" fontSize="10" isBold="false" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0" lineColor="#000000"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+		<conditionalStyle>
+			<conditionExpression><![CDATA[new Boolean($V{REPORT_COUNT}.intValue()%2==0)]]></conditionExpression>
+			<style isDefault="false" style="table_TD" backcolor="#F7F7F7"/>
+		</conditionalStyle>
+	</style>
+	<style name="table_CF" isDefault="false" mode="Opaque" backcolor="#EDEDED" fontSize="12" isBold="true" isItalic="false" isUnderline="false" isStrikeThrough="false">
+		<box topPadding="0" leftPadding="0" bottomPadding="0" rightPadding="0">
+			<pen lineWidth="1.0"/>
+			<topPen lineWidth="1.0"/>
+			<leftPen lineWidth="0.0"/>
+			<bottomPen lineWidth="1.0"/>
+			<rightPen lineWidth="0.0"/>
+		</box>
+	</style>
+	<subDataset name="dataset1">
+		<field name="description" class="java.lang.String"/>
+	</subDataset>
+	<parameter name="reportTitle" class="java.lang.String"/>
+	<parameter name="currentUser" class="java.lang.String"/>
+	<parameter name="logoUrl" class="java.lang.String"/>
+	<parameter name="startDateString" class="java.lang.String"/>
+	<parameter name="endDateString" class="java.lang.String"/>
+	<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
+		<defaultValueExpression><![CDATA["C:\\Documents and Settings\\kromhoutg\\My Documents\\reports\\"]]></defaultValueExpression>
+	</parameter>
+	<queryString language="SQL">
+		<![CDATA[]]>
+	</queryString>
+	<field name="summaryOfCalculationMethod" class="java.lang.String"/>
+	<field name="dataList" class="java.util.List"/>
+	<background>
+		<band splitType="Stretch"/>
+	</background>
+	<pageHeader>
+		<band height="121" splitType="Stretch">
+			<textField>
+				<reportElement key="staticText-1" x="0" y="57" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+			<image>
+				<reportElement x="0" y="0" width="340" height="57"/>
+				<imageExpression class="java.net.URL"><![CDATA[new URL($P{logoUrl})]]></imageExpression>
+			</image>
+			<textField pattern="dd-MMM-yyyy" isBlankWhenNull="true">
+				<reportElement x="0" y="87" width="340" height="20"/>
+				<textElement textAlignment="Center" verticalAlignment="Middle" markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{startDateString}+" to "+$P{endDateString}]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageHeader>
+	<columnHeader>
+		<band splitType="Stretch"/>
+	</columnHeader>
+	<detail>
+		<band height="268" splitType="Stretch">
+			<componentElement>
+				<reportElement x="0" y="0" width="535" height="26"/>
+				<jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
+					<datasetRun subDataset="dataset1">
+						<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{dataList})]]></dataSourceExpression>
+					</datasetRun>
+					<jr:listContents height="26" width="535">
+						<textField>
+							<reportElement x="0" y="0" width="400" height="20"/>
+							<textElement>
+								<font fontName="Serif"/>
+							</textElement>
+							<textFieldExpression class="java.lang.String"><![CDATA[$F{description}]]></textFieldExpression>
+						</textField>
+					</jr:listContents>
+				</jr:list>
+			</componentElement>
+		</band>
+	</detail>
+	<columnFooter>
+		<band splitType="Stretch"/>
+	</columnFooter>
+	<pageFooter>
+		<band height="40" splitType="Stretch">
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="415" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+			<textField evaluationTime="Report">
+				<reportElement x="495" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+		</band>
+	</pageFooter>
+	<lastPageFooter>
+		<band height="40">
+			<textField evaluationTime="Report">
+				<reportElement x="495" y="20" width="40" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[" " + $V{PAGE_NUMBER}]]></textFieldExpression>
+			</textField>
+			<textField pattern="dd-MMM-yyyy">
+				<reportElement x="82" y="0" width="200" height="20"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.util.Date"><![CDATA[new java.util.Date()]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="0" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Generated: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="20" width="82" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["By: "]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="82" y="20" width="200" height="20"/>
+				<textElement markup="none">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{currentUser}]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="415" y="20" width="80" height="20"/>
+				<textElement textAlignment="Right">
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Page "+$V{PAGE_NUMBER}+" of"]]></textFieldExpression>
+			</textField>
+		</band>
+	</lastPageFooter>
+	<summary>
+		<band height="369">
+			<textField>
+				<reportElement key="staticText-1" x="97" y="11" width="340" height="30"/>
+				<textElement textAlignment="Center" verticalAlignment="Top" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["Summary of Calculation Method"]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement x="0" y="50" width="535" height="311"/>
+				<textElement>
+					<font fontName="Serif"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$F{summaryOfCalculationMethod}]]></textFieldExpression>
+			</textField>
+		</band>
+	</summary>
+	<noData>
+		<band height="85" splitType="Stretch">
+			<textField>
+				<reportElement x="0" y="35" width="535" height="50"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="14" isBold="true"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA["No data to display. \n"+
+"Please run report again."]]></textFieldExpression>
+			</textField>
+			<textField>
+				<reportElement key="staticText-1" x="0" y="0" width="535" height="35"/>
+				<textElement textAlignment="Center" markup="none">
+					<font fontName="Serif" size="20"/>
+				</textElement>
+				<textFieldExpression class="java.lang.String"><![CDATA[$P{reportTitle}]]></textFieldExpression>
+			</textField>
+		</band>
+	</noData>
+</jasperReport>
