<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>racetrack_ch3/grails-app/conf/RacetrackUrlMappings.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch3/grails-app/i18n/messages_de.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch3/grails-app/i18n/messages_fr.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch3/grails-app/i18n/messages_ja.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch3/grails-app/i18n/messages_nl.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch3/grails-app/i18n/messages_ru.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch3/grails-app/i18n/messages_zh_CN.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch3/plugins/core/grails-app/utils/Base64Codec.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch3/web-app/WEB-INF/templates/scaffolding/Controller.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch3/web-app/WEB-INF/templates/scaffolding/create.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch3/web-app/WEB-INF/templates/scaffolding/edit.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch3/web-app/WEB-INF/templates/scaffolding/list.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch3/web-app/WEB-INF/templates/scaffolding/show.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch3/web-app/index.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch4/grails-app/conf/RacetrackUrlMappings.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch4/grails-app/i18n/messages_de.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch4/grails-app/i18n/messages_fr.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch4/grails-app/i18n/messages_ja.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch4/grails-app/i18n/messages_nl.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch4/grails-app/i18n/messages_ru.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch4/grails-app/i18n/messages_zh_CN.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch4/plugins/core/grails-app/utils/Base64Codec.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch4/web-app/WEB-INF/templates/scaffolding/Controller.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch4/web-app/WEB-INF/templates/scaffolding/create.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch4/web-app/WEB-INF/templates/scaffolding/edit.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch4/web-app/WEB-INF/templates/scaffolding/list.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch4/web-app/WEB-INF/templates/scaffolding/show.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch4/web-app/index.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch5/grails-app/conf/RacetrackUrlMappings.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch5/grails-app/i18n/messages_de.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch5/grails-app/i18n/messages_fr.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch5/grails-app/i18n/messages_ja.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch5/grails-app/i18n/messages_nl.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch5/grails-app/i18n/messages_ru.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch5/grails-app/i18n/messages_zh_CN.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch5/plugins/core/grails-app/utils/Base64Codec.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch5/web-app/WEB-INF/templates/scaffolding/Controller.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch5/web-app/WEB-INF/templates/scaffolding/create.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch5/web-app/WEB-INF/templates/scaffolding/edit.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch5/web-app/WEB-INF/templates/scaffolding/list.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch5/web-app/WEB-INF/templates/scaffolding/show.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch5/web-app/index.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch6/grails-app/conf/RacetrackUrlMappings.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch6/grails-app/i18n/messages_de.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch6/grails-app/i18n/messages_fr.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch6/grails-app/i18n/messages_ja.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch6/grails-app/i18n/messages_nl.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch6/grails-app/i18n/messages_ru.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch6/grails-app/i18n/messages_zh_CN.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch6/plugins/core/grails-app/utils/Base64Codec.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch6/web-app/WEB-INF/templates/scaffolding/Controller.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch6/web-app/WEB-INF/templates/scaffolding/create.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch6/web-app/WEB-INF/templates/scaffolding/edit.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch6/web-app/WEB-INF/templates/scaffolding/list.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch6/web-app/WEB-INF/templates/scaffolding/show.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch6/web-app/index.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch7/grails-app/conf/RacetrackUrlMappings.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch7/grails-app/i18n/messages_de.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch7/grails-app/i18n/messages_fr.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch7/grails-app/i18n/messages_ja.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch7/grails-app/i18n/messages_nl.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch7/grails-app/i18n/messages_ru.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch7/grails-app/i18n/messages_zh_CN.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch7/plugins/core/grails-app/utils/Base64Codec.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/TEST-RaceControllerTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/TEST-RaceTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/TEST-RegistrationControllerTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/TEST-RegistrationTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/TEST-UserTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/plain/TEST-RaceControllerTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/plain/TEST-RaceTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/plain/TEST-RegistrationControllerTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/plain/TEST-RegistrationTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch7/target/test-reports/plain/TEST-UserTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch7/web-app/WEB-INF/templates/scaffolding/Controller.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch7/web-app/WEB-INF/templates/scaffolding/create.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch7/web-app/WEB-INF/templates/scaffolding/edit.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch7/web-app/WEB-INF/templates/scaffolding/list.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch7/web-app/WEB-INF/templates/scaffolding/show.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch7/web-app/index.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch8/grails-app/conf/RacetrackUrlMappings.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch8/grails-app/i18n/messages_de.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch8/grails-app/i18n/messages_fr.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch8/grails-app/i18n/messages_ja.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch8/grails-app/i18n/messages_nl.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch8/grails-app/i18n/messages_ru.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch8/grails-app/i18n/messages_zh_CN.properties</filename>
    </added>
    <added>
      <filename>racetrack_ch8/plugins/core/grails-app/utils/Base64Codec.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch8/prodDb.script</filename>
    </added>
    <added>
      <filename>racetrack_ch8/racetrack-0.1.war</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/TEST-RaceControllerTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/TEST-RaceTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/TEST-RegistrationControllerTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/TEST-RegistrationTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/TEST-UserTests.xml</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/plain/TEST-RaceControllerTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/plain/TEST-RaceTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/plain/TEST-RegistrationControllerTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/plain/TEST-RegistrationTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch8/target/test-reports/plain/TEST-UserTests.txt</filename>
    </added>
    <added>
      <filename>racetrack_ch8/web-app/WEB-INF/templates/scaffolding/Controller.groovy</filename>
    </added>
    <added>
      <filename>racetrack_ch8/web-app/WEB-INF/templates/scaffolding/create.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch8/web-app/WEB-INF/templates/scaffolding/edit.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch8/web-app/WEB-INF/templates/scaffolding/list.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch8/web-app/WEB-INF/templates/scaffolding/show.gsp</filename>
    </added>
    <added>
      <filename>racetrack_ch8/web-app/index.gsp</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -10,7 +10,9 @@
 	&lt;classpathentry kind=&quot;src&quot; path=&quot;grails-tests&quot;/&gt;
 	&lt;classpathentry kind=&quot;con&quot; path=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot;/&gt;
 	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/ant/lib/ant.jar&quot;/&gt;
-    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
+    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-junit.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant.jar&quot; /&gt;
 
@@ -48,9 +50,9 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ejb3-persistence.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.2-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.5-SNAPSHOT.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.0.1-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.1-BETA-1.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-starter.jar&quot; /&gt;
 
@@ -80,13 +82,13 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/log4j-1.2.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ognl-2.7.jar&quot; /&gt;
-
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/org.mortbay.jetty.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/oro-2.0.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.5.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.6.0.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/serializer.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/servletapi-2.4.jar&quot; /&gt;
 
@@ -106,18 +108,20 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/standard-2.4.jar&quot; /&gt;
 
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xalan.jar&quot; /&gt;
+
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xerces-2.6.2.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xml-apis.jar&quot; /&gt;
 
 
-	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.4.2.jar&quot; /&gt;
+	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.5.jar&quot; /&gt;
 
 
 	&lt;classpathentry kind=&quot;output&quot; path=&quot;web-app/WEB-INF/classes&quot;/&gt;</diff>
      <filename>racetrack_ch3/.classpath</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-#Do not edit app.grails.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place!
-#Sun Mar 11 15:49:46 EDT 2007
-app.grails.version=0.4.2
+#Wed May 02 20:22:50 EDT 2007
+app.version=0.1
+app.grails.version=0.5
 app.name=racetrack</diff>
      <filename>racetrack_ch3/application.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class DevelopmentDataSource { 
+class DevelopmentDataSource {
    boolean pooling = true 
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_dev&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
    String password = &quot;&quot; 
-} 
+}</diff>
      <filename>racetrack_ch3/grails-app/conf/DevelopmentDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch3/grails-app/conf/log4j.development.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch3/grails-app/conf/log4j.production.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch3/grails-app/conf/log4j.test.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Race {  
+class Race { 
     String name 
     Date startDateTime 
     String city 
@@ -7,16 +7,16 @@ class Race {
     Float cost 
     Integer maxRunners = 100000 
      
-    static hasMany = [registrations:Registration]  
+    static hasMany = [registrations:Registration]
     
     static constraints = { 
-        name(maxLength:50,blank:false) 
-        startDateTime(validator: {return (it &gt; new Date())})  
-        city(maxLength:30,blank:false) 
+        name(maxSize:50,blank:false) 
+        startDateTime(validator: {return (it &gt; new Date())}) 
+        city(maxSize:30,blank:false) 
         state(inList:['GA', 'NC', 'SC', 'VA'],blank:false) 
         distance(min:3.1f,max:100f) 
         cost(min:0f,max:999.99f) 
-    }
+    } 
     
-    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot;}     
-}
\ No newline at end of file
+    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot; }
+}	</diff>
      <filename>racetrack_ch3/grails-app/domain/Race.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Registration  {  
+class Registration { 
     Race race 
     String name 
     Date dateOfBirth 
@@ -6,19 +6,17 @@ class Registration  {
     String postalAddress 
     String emailAddress 
     Date createdAt = new Date() 
-    
+
     static belongsTo = Race 
-    
-    static optionals = [&quot;postalAddress&quot; ]  
-    
+
     static constraints = { 
-        name(maxLength:50,blank:false) 
+        name(maxSize:50,blank:false) 
         dateOfBirth(nullable:false) 
         gender(inList:[&quot;M&quot;, &quot;F&quot;]) 
-        postalAddress(maxLength:255) 
-        emailAddress(maxLength:50,email:true) 
+        postalAddress(nullable:true,maxSize:255) 
+        emailAddress(maxSize:50,email:true) 
         race(nullable:false) 
     } 
-
-  String toString() {&quot;${this.name} : ${this.emailAddress}&quot;}         
-}
\ No newline at end of file
+    
+    String toString(){&quot;${this.name}:${this.emailAddress}&quot;}         
+}	</diff>
      <filename>racetrack_ch3/grails-app/domain/Registration.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,20 +1,19 @@
 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.message=Property [{0}] of class [{1}] is not a valid [{2}].
+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.length.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
-default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
 default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
-default.invalid.max.length.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
-default.invalid.min.length.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{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.not.editable.message=Property [{0}] of class [{1}] with value [{2}] cannot be changed from [{3}] 
\ No newline at end of file
+
+default.paginate.prev=Previous
+default.paginate.next=Next</diff>
      <filename>racetrack_ch3/grails-app/i18n/messages.properties</filename>
    </modified>
    <modified>
      <diff>@@ -27,19 +27,19 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch3/grails-app/views/race/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -33,19 +33,19 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='registrations'&gt;Registrations:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'registrations','errors')}'&gt;&lt;ul&gt;
     &lt;g:each var='r' in='${race?.registrations?}'&gt;</diff>
      <filename>racetrack_ch3/grails-app/views/race/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -20,21 +20,20 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                   
-                                      
-                        &lt;th&gt;Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Start Date Time&lt;/th&gt;
-                                      
-                        &lt;th&gt;City&lt;/th&gt;
-                                      
-                        &lt;th&gt;State&lt;/th&gt;
-                                      
-                        &lt;th&gt;Distance&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+               
+                   	    &lt;g:sortableColumn property=&quot;id&quot; title=&quot;Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;startDateTime&quot; title=&quot;Start Date Time&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;city&quot; title=&quot;City&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;state&quot; title=&quot;State&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;distance&quot; title=&quot;Distance&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch3/grails-app/views/race/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -27,7 +27,7 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -35,7 +35,7 @@
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        </diff>
      <filename>racetrack_ch3/grails-app/views/registration/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -33,7 +33,7 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -41,7 +41,7 @@
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        </diff>
      <filename>racetrack_ch3/grails-app/views/registration/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -20,21 +20,20 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                   
-                                      
-                        &lt;th&gt;Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Date Of Birth&lt;/th&gt;
-                                      
-                        &lt;th&gt;Gender&lt;/th&gt;
-                                      
-                        &lt;th&gt;Postal Address&lt;/th&gt;
-                                      
-                        &lt;th&gt;Email Address&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+               
+                   	    &lt;g:sortableColumn property=&quot;id&quot; title=&quot;Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;dateOfBirth&quot; title=&quot;Date Of Birth&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;gender&quot; title=&quot;Gender&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;postalAddress&quot; title=&quot;Postal Address&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;emailAddress&quot; title=&quot;Email Address&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch3/grails-app/views/registration/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,10 @@ import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
-class ApplicationTagLib {
+class ApplicationTagLib { 
+	
+	def grailsUrlMappingsHolder
+	
     /**
      * Creates a link to a resource, generally used as a method rather than a tag.
      *
@@ -33,7 +36,7 @@ class ApplicationTagLib {
      */
     def createLinkTo = { attrs -&gt;
          out &lt;&lt; grailsAttributes.getApplicationUri(request)
-         if(attrs['dir']) {
+         if(attrs['dir'] || attrs['dir'] == '') {
             out &lt;&lt; &quot;/${attrs['dir']}&quot;
          }
          if(attrs['file']) {
@@ -50,7 +53,7 @@ class ApplicationTagLib {
     def link = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;a href=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // process remaining attributes
@@ -59,7 +62,7 @@ class ApplicationTagLib {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -79,29 +82,47 @@ class ApplicationTagLib {
         if(attrs['url']) {
              attrs = attrs.remove('url')
         }
-        // if the current attribute null set the controller uri to the current controller
-        if(attrs[&quot;controller&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;controller&quot;)
-        }
-        else {
-           out &lt;&lt; grailsAttributes.getControllerUri(request)
-        }
-        if(attrs[&quot;action&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;action&quot;)
-        }
-        if(attrs[&quot;id&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;id&quot;)
-        }
-        if(attrs['params']) {
-            def pms = attrs.remove('params')
-            out &lt;&lt; '?'
-            def i = 0
-            pms.each { k,v -&gt;
-                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
-                if(++i &lt; pms.size())
-                   out &lt;&lt; '&amp;'
-            }
-        }
+                                                     
+		def controller = attrs.containsKey(&quot;controller&quot;) ? attrs.remove(&quot;controller&quot;) : grailsAttributes.getController(request).controllerName
+		def action = attrs.remove(&quot;action&quot;)
+        def id = attrs.remove(&quot;id&quot;)
+        def params = attrs.params ? attrs.remove('params') : [:]
+
+        def url
+		try {
+            if(id) params.id = id
+            def mapping = grailsUrlMappingsHolder?.getReverseMapping(controller,action,params)
+			params.controller = controller
+			if(action) params.action = action  
+            url = mapping?.createURL(params)
+		}        
+		finally {
+			params.remove('controller')
+			params.remove('action')          
+			params.remove('id')
+		}
+		if(url) {
+			out &lt;&lt; url
+		}             
+		else {
+            out &lt;&lt; '/' &lt;&lt; controller
+	        if(action) {
+	            out &lt;&lt; '/' &lt;&lt; action
+	        }
+	        if(id) {
+	            out &lt;&lt; '/' &lt;&lt; id
+	        }
+	        if(params) {
+	            out &lt;&lt; '?'
+	            def i = 0
+	            params.each { k,v -&gt;
+	                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
+	                if(++i &lt; params.size())
+	                   out &lt;&lt; '&amp;'
+	            }
+	        }			
+		}
+															
     }
 
 	/**
@@ -127,8 +148,8 @@ class ApplicationTagLib {
 				} 				
 			}
 		}
-		out &lt;&lt; '&gt;'
-		body()
+		out &lt;&lt; '&gt;'  
+		out &lt;&lt; body()
 		out &lt;&lt; &quot;&lt;/${attrs.name}&gt;&quot;			
 	}	
 }</diff>
      <filename>racetrack_ch3/plugins/core/grails-app/taglib/ApplicationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -16,6 +16,7 @@ import org.springframework.validation.Errors;
 import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
+import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
 
  /**
  *  A  tag lib that provides tags for working with form controls
@@ -33,7 +34,10 @@ class FormTagLib {
 	def textField = { attrs -&gt;
 		attrs.type = &quot;text&quot;  
 		attrs.tagName = &quot;textField&quot; 
-		field(attrs)
+		def result = field(attrs)
+		if(result) {     
+			out &lt;&lt; result
+		}
 	}
 	/**
 	 * Creates a hidden field
@@ -41,7 +45,7 @@ class FormTagLib {
 	def hiddenField = { attrs -&gt;
 		attrs.type = &quot;hidden&quot;
 		attrs.tagName = &quot;hiddenField&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * Creates a submit button
@@ -49,7 +53,7 @@ class FormTagLib {
 	def submitButton = { attrs -&gt;
 		attrs.type = &quot;submit&quot;
 		attrs.tagName = &quot;submitButton&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * A general tag for creating fields
@@ -84,7 +88,7 @@ class FormTagLib {
     void resolveAttributes(attrs)
     {
         if(!attrs.name &amp;&amp; !attrs.field) {
-            throwTagError(&quot;Tag [$tagName] is missing required attribute [name] or [field]&quot;)
+            throwTagError(&quot;Tag [${attrs.tagName}] is missing required attribute [name] or [field]&quot;)
         }
         attrs.remove('tagName')
 
@@ -121,7 +125,7 @@ class FormTagLib {
     def form = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;form action=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // default to post
@@ -133,26 +137,34 @@ class FormTagLib {
 
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        def bodyContent = body()
+		out &lt;&lt; bodyContent
 
         // close tag
         out &lt;&lt; &quot;&lt;/form&gt;&quot;
     }
     /**
      * Creates a submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmit value=&quot;Edit&quot; /&gt;
+     *  &lt;g:actionSubmit action=&quot;Edit&quot; value=&quot;Some label for editing&quot; /&gt;
      *
      */
     def actionSubmit = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;submit&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+    	if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
-        // process remaining attributes
+
+		// add action and value
+		def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    	
+    	out &lt;&lt; &quot;&lt;input type=\&quot;submit\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+    	
+    	// process remaining attributes
         outputAttributes(attrs)
 
         // close tag
@@ -161,22 +173,30 @@ class FormTagLib {
     }
     /**
      * Creates a an image submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmitImage src=&quot;/images/submitButton.gif&quot; action=&quot;Edit&quot; /&gt;
      *
      */
     def actionSubmitImage = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;image&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+        if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
+        
+        // add action and value
+        def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    
+        out &lt;&lt; &quot;&lt;input type=\&quot;image\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+
+		// add image src        
         def src = attrs.remove('src')
         if(src) {
              out &lt;&lt; &quot;src=\&quot;${src}\&quot; &quot;
         }
+
         // process remaining attributes
         outputAttributes(attrs)
 
@@ -201,6 +221,8 @@ class FormTagLib {
 
         def value = (attrs['value'] ? attrs['value'] : xdefault)
         def name = attrs['name']
+        def id = attrs['id'] ? attrs['id'] : name
+
 		def noSelection = attrs['noSelection']
 		if (noSelection != null)
 		{
@@ -253,7 +275,7 @@ class FormTagLib {
 
         // create day select
         if (precision &gt;= PRECISION_RANKINGS[&quot;day&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_day\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_day\&quot; id=\&quot;${id}_day\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -272,7 +294,7 @@ class FormTagLib {
 
         // create month select
         if (precision &gt;= PRECISION_RANKINGS[&quot;month&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_month\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_month\&quot; id=\&quot;${id}_month\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -294,7 +316,7 @@ class FormTagLib {
 
         // create year select
         if (precision &gt;= PRECISION_RANKINGS[&quot;year&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_year\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_year\&quot; id=\&quot;${id}_year\&quot;&gt;&quot;
 
             if (noSelection) {
     			renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -313,7 +335,7 @@ class FormTagLib {
 
         // do hour select
         if (precision &gt;= PRECISION_RANKINGS[&quot;hour&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot; id=\&quot;${id}_hour\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -338,7 +360,7 @@ class FormTagLib {
 
         // do minute select
         if (precision &gt;= PRECISION_RANKINGS[&quot;minute&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot; id=\&quot;${id}_minute\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -360,7 +382,7 @@ class FormTagLib {
 	def renderNoSelectionOption = { noSelectionKey, noSelectionValue, value -&gt;
 		// If a label for the '--Please choose--' first item is supplied, write it out
         out &lt;&lt; '&lt;option value=&quot;' &lt;&lt; (noSelectionKey == null ? &quot;&quot; : noSelectionKey) &lt;&lt; '&quot;'
-        if(noSelectionKey == value) {
+        if(noSelectionKey.equals(value)) {
             out &lt;&lt; ' selected=&quot;selected&quot; '
         }
         out &lt;&lt; '&gt;' &lt;&lt; noSelectionValue.encodeAsHTML() &lt;&lt; '&lt;/option&gt;'
@@ -388,7 +410,7 @@ class FormTagLib {
         }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -405,7 +427,7 @@ class FormTagLib {
         attrs['optionValue'] = { &quot;${it.language}, ${it.country},  ${it.displayName}&quot; }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -425,7 +447,7 @@ class FormTagLib {
 		   	attrs.value = null
 		}
         // invoke generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -436,11 +458,15 @@ class FormTagLib {
      * &lt;g:select name=&quot;user.company.id&quot; from=&quot;${Company.list()}&quot; value=&quot;${user?.company.id}&quot; optionKey=&quot;id&quot; /&gt;
      */
     def select = { attrs -&gt;
+	    def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request)
+
         def from = attrs.remove('from')
         def keys = attrs.remove('keys')
         def optionKey = attrs.remove('optionKey')
         def optionValue = attrs.remove('optionValue')
         def value = attrs.remove('value')
+        def valueMessagePrefix = attrs.remove('valueMessagePrefix')
 		def noSelection = attrs.remove('noSelection')
         if (noSelection != null) {
             noSelection = noSelection.entrySet().iterator().next()
@@ -461,20 +487,21 @@ class FormTagLib {
         // create options from list
         if(from) {
             from.eachWithIndex { el,i -&gt;
+            	def keyValue = null
                 out &lt;&lt; '&lt;option '
                 if(keys) {
-                    out &lt;&lt; 'value=&quot;' &lt;&lt; keys[i] &lt;&lt; '&quot; '
-                    if(keys[i] == value) {
+                    keyValue = keys[i]
+                    out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
-               else if(optionKey) {
-                    def keyValue = null
+                else if(optionKey) {
                     if(optionKey instanceof Closure) {
                         keyValue = optionKey(el)
-                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                        out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
-                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getGrailsDomainClass(el.getClass().name)) {
+                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, el.getClass().name)) {
                         keyValue = el.ident()
                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
@@ -488,8 +515,9 @@ class FormTagLib {
                     }
                 }
                 else {
-                    out &lt;&lt; &quot;value=\&quot;${el}\&quot; &quot;
-                    if(el == value) {
+                	keyValue = el
+                    out &lt;&lt; &quot;value=\&quot;${keyValue}\&quot; &quot;
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
@@ -502,6 +530,19 @@ class FormTagLib {
                         out &lt;&lt; el.properties[optionValue].toString().encodeAsHTML()
                     }
                 }
+                else if(valueMessagePrefix) {
+                	def message = messageSource.getMessage(&quot;${valueMessagePrefix}.${keyValue}&quot;, null, null, locale)
+                	if(message) {
+                		out &lt;&lt; message.encodeAsHTML()
+                	}
+                	else if (keyValue) {
+                		out &lt;&lt; keyValue.encodeAsHTML()
+                	}
+					else {
+        	            def s = el.toString()
+    	                if(s) out &lt;&lt; s.encodeAsHTML()
+	                }
+                }
                 else {
                     def s = el.toString()
                     if(s) out &lt;&lt; s.encodeAsHTML()
@@ -554,6 +595,6 @@ class FormTagLib {
         outputAttributes(attrs)
 
         // close the tag, with no body
-        out &lt;&lt; ' &gt;&lt;/input&gt;'
+        out &lt;&lt; ' /&gt;'
      }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch3/plugins/core/grails-app/taglib/FormTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ class JavascriptTagLib  {
 		}
 		else {
 			out.println '&lt;script type=&quot;text/javascript&quot;&gt;'
-				body()
+				out &lt;&lt; body()
 			out.println '&lt;/script&gt;'
 		}
 	}
@@ -137,15 +137,15 @@ class JavascriptTagLib  {
     /**
      * A link to a remote uri that used the prototype library to invoke the link via ajax
      */
-    def remoteLink = { attrs, body -&gt;
+    def remoteLink = { attrs, body -&gt;  
        out &lt;&lt; &quot;&lt;a href=\&quot;&quot;    
 
        def cloned = deepClone(attrs)
-	   createLink(cloned)               
+	   out &lt;&lt; createLink(cloned)               
 
 	   out &lt;&lt; &quot;\&quot; onclick=\&quot;&quot;
         // create remote function
-        remoteFunction(attrs)   
+        out &lt;&lt; remoteFunction(attrs)   
 		attrs.remove('url')
         out &lt;&lt; &quot;return false;\&quot; &quot;
         // process remaining attributes
@@ -154,7 +154,7 @@ class JavascriptTagLib  {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -180,7 +180,7 @@ class JavascriptTagLib  {
 		else {
     		attrs.params = &quot;'${paramName}='+this.value&quot;			
 		}
-		remoteFunction(attrs)
+		out &lt;&lt; remoteFunction(attrs)
 		attrs.remove('params')
 		out &lt;&lt; &quot;\&quot;&quot;   
 		attrs.remove('url')
@@ -208,16 +208,16 @@ class JavascriptTagLib  {
 		// prepare form settings
 		prepareAjaxForm(p,attrs)
         
-        def params = [  onsubmit:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onsubmit:remoteFunction(attrs) + 'return false',
 					    method: (attrs.method? attrs.method : 'POST' ),
-					    action: (attrs.action? attrs.action : TagLibUtil.outToString(createLink,url))		                 
+					    action: (attrs.action? attrs.action : createLink(url))		                 
 		             ]
 		attrs.remove('url')		             
 	    params.putAll(attrs)
 		if(params.name &amp;&amp; !params.id)
 			params.id = params.name
-	    withTag(name:'form',attrs:params) {
-			body()   
+	    out &lt;&lt; withTag(name:'form',attrs:params) {
+			out &lt;&lt; body()   
 	    }		
     }
 
@@ -230,7 +230,7 @@ class JavascriptTagLib  {
 		// prepare form settings 
 		attrs.forSubmitTag = &quot;.form&quot;
 		prepareAjaxForm(p,attrs)    
-        def params = [  onclick:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onclick:remoteFunction(attrs) + 'return false',
 					    type: 'button',
 					    name: attrs.remove('name'),
 					    value: attrs.remove('value'), 
@@ -238,8 +238,8 @@ class JavascriptTagLib  {
 					    'class':attrs.remove('class')
 		             ]
 		             
-		withTag(name:'input', attrs:params) {
-			body()	
+		out &lt;&lt; withTag(name:'input', attrs:params) {
+			out &lt;&lt; body()	
 		}
     }
 	
@@ -275,7 +275,7 @@ class JavascriptTagLib  {
 			def sw = new StringWriter()
 			out = new PrintWriter(out)
 			// invoke body
-			body()
+			out &lt;&lt; body()
 			// restore out
 			out = tmp
 			js = sw.toString()
@@ -357,10 +357,10 @@ class PrototypeProvider implements JavascriptProvider {
 		
 		def pms = attrs.remove('params')   
 		if(attrs.url) {
-			taglib.createLink(attrs.url)			
+			out &lt;&lt; taglib.createLink(attrs.url)			
 		}                              
 		else {
-			taglib.createLink(attrs)			
+			out &lt;&lt; taglib.createLink(attrs)			
 		}
 
 		
@@ -415,6 +415,7 @@ class PrototypeProvider implements JavascriptProvider {
 	                    case 'true': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case 'false': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case ~/\s*function(\w*)\s*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
+	                    case ~/Insertion\..*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    default:ajaxOptions &lt;&lt; &quot;${k}:'${v}'&quot;; break;
 	                 }            	
             	}
@@ -441,10 +442,10 @@ class YahooProvider implements JavascriptProvider {
 		out &lt;&lt; &quot;YAHOO.util.Connect.asyncRequest('${method}','&quot;
 				
 		if(attrs.url) {
-			taglib.createLink(attrs.url)
+			out &lt;&lt; taglib.createLink(attrs.url)
 		}
 		else {
-			taglib.createLink(attrs)
+			out &lt;&lt; taglib.createLink(attrs)
 		}		
 		attrs.remove('url')
 		out &lt;&lt; &quot;',&quot;
@@ -504,7 +505,7 @@ class DojoProvider implements JavascriptProvider {
 		}		
 		 out &lt;&lt; 'dojo.io.bind({url:\''
 
-		 taglib.createLink(attrs) 
+		 out &lt;&lt; taglib.createLink(attrs) 
 		attrs.remove('params')
 		 out &lt;&lt; '\',load:function(type,data,evt) {'
 	    if(attrs.onLoaded) {</diff>
      <filename>racetrack_ch3/plugins/core/grails-app/taglib/JavascriptTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,6 +25,7 @@ import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
 class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants {
+	def out // to facilitate testing
 
     protected getPage() {
     	return request[PAGE]
@@ -91,7 +92,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 				}
 			}
 			if(invokeBody) {
-				body();	
+				out &lt;&lt; body()
 			}
 		}
 	}
@@ -134,54 +135,183 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         if(attrs.total == null)
             throwTagError(&quot;Tag [paginate] is missing required attribute [total]&quot;)
 		
-		def mkp = new groovy.xml.MarkupBuilder(out)
+		def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request) 
+		
 		def total = attrs.total.toInteger()
-		def max = params.max?.toInteger()
-		def offset = params.offset?.toInteger() 
 		def action = (attrs.action? attrs.action : 'list')
-		def breadcrumb = true
-		if(attrs.breadcrumb) breadcrumb = Boolean.valueOf(attrs.breadcrumb)
-			
+		def offset = params.offset?.toInteger()
+		def max = params.max?.toInteger()
+		def maxsteps = (attrs.maxsteps ? attrs.maxsteps.toInteger() : 10)
+
+        if(attrs.breadcrumb) {
+			log.warn(&quot;Tag [paginate] includes the [breadcrumb] attribute. This attribute is deprecated and will be removed in the future. Please update your code to use the [maxsteps] attribute instead.&quot;)
+		}
+
+		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)			
 		if(!max) max = (attrs.max ? attrs.max.toInteger() : 10)
-		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)
 		
-		def linkParams = [offset:offset-max,max:max]
-		def linkTagAttrs = ['class':'prevLink',action:action]
+		def linkParams = [offset:offset - max, max:max]
+		if(params.sort) linkParams.sort = params.sort
+		if(params.order) linkParams.order = params.order
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		def linkTagAttrs = [action:action]
 		if(attrs.controller) {
 			linkTagAttrs.controller = attrs.controller	
 		}
 		if(attrs.id) {
 			linkTagAttrs.id = attrs.id	
 		}
-		if(attrs.params)linkParams.putAll(attrs.params)
 		linkTagAttrs.params = linkParams
-	
-		def combined = max + offset
-		if(offset &gt; 0) {			
-			link(linkTagAttrs.clone(),{out&lt;&lt; (attrs.prev? attrs.prev : 'Previous' ) })
+		
+		// determine paging variables
+		def steps = maxsteps &gt; 0
+		int currentstep = (offset / max) + 1
+		int firststep = 1
+		int laststep = Math.round(Math.ceil(total / max))
+			
+		// display previous link when not on firststep
+		if(currentstep &gt; firststep) {
+			linkTagAttrs.class = 'prevLink'
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.prev ? attrs.prev : messageSource.getMessage('default.paginate.prev', null, 'Previous', locale))
+			 }
 		}
 		
-		if(total &gt; max) {
-			linkTagAttrs.'class' = 'step'
-			if(breadcrumb) {
-				def j = 0
-				0.step(total,max) { i -&gt;
-					if(offset == i) {
-						mkp.a('class':'step',&quot;${++j}&quot;)	
-					}
-					else {
-						linkParams.offset=i
-						link(linkTagAttrs.clone(),{out&lt;&lt;++j})	
-					}
-				}			
+		// display steps when steps are enabled and laststep is not firststep
+		if(steps &amp;&amp; laststep &gt; firststep) {
+			linkTagAttrs.class = 'step'
+
+			// determine begin and endstep paging variables
+			int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
+			int endstep = currentstep + Math.round(maxsteps / 2) - 1
+			
+			if(beginstep &lt; firststep) {
+				beginstep = firststep
+				endstep = maxsteps
+			}
+			if(endstep &gt; laststep) {
+				beginstep = laststep - maxsteps + 1
+				if(beginstep &lt; firststep) {
+					beginstep = firststep
+				}
+				endstep = laststep
+			}
+
+			// display firststep link when beginstep is not firststep
+			if(beginstep &gt; firststep) {
+				linkParams.offset = 0
+				out &lt;&lt; link(linkTagAttrs.clone()) {firststep.toString()}
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+			}
+
+			// display paginate steps
+			(beginstep..endstep).each { i -&gt;
+				if(currentstep == i) {
+					out &lt;&lt; &quot;&lt;span class=\&quot;currentStep\&quot;&gt;${i}&lt;/span&gt;&quot;
+				}
+				else {
+					linkParams.offset = (i - 1) * max
+					out &lt;&lt; link(linkTagAttrs.clone()) {i.toString()}
+				}
+			}	
+			
+			// display laststep link when endstep is not laststep
+			if(endstep &lt; laststep) {
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+				linkParams.offset = (laststep -1) * max
+				out &lt;&lt; link(linkTagAttrs.clone()) { laststep.toString() }
+			}		
+		}
+		
+		// display next link when not on laststep
+		if(currentstep &lt; laststep) {	
+			linkTagAttrs.class = 'nextLink'			
+			linkParams.offset = offset + max
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.next ? attrs.next : messageSource.getMessage('default.paginate.next', null, 'Next', locale))
 			}			
 		}
-		linkParams.offset = offset+max
-		if(combined &lt; total) {	
-			linkTagAttrs.'class'='nextLink'			
-			link(linkTagAttrs,{out&lt;&lt; (attrs.'next'? attrs.'next' : 'Next' )})			
+
+	}
+
+	/**
+	 * Renders a sortable column to support sorting in list views
+	 *
+	 * Attributes:
+	 *
+	 * property - name of the property relating to the field
+	 * defaultOrder (optional) - default order for the property; choose between asc (default if not provided) and desc
+	 * title (optional*) - title caption for the column
+	 * titleKey (optional*) - title key to use for the column, resolved against the message source
+	 * params (optional) - a map containing request parameters
+	 *
+	 * Attribute title or titleKey is required. When both attributes are specified then titleKey takes precedence,
+	 * resulting in the title caption to be resolved against the message source. In case when the message could
+	 * not be resolved, the title will be used as title caption. 
+	 *
+	 * Examples:
+	 *
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; style=&quot;width: 200px&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; titleKey=&quot;book.title&quot; /&gt;	 
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; titleKey=&quot;book.releaseDate&quot; /&gt;
+	 */
+	def sortableColumn = { attrs -&gt;
+
+		if(!attrs.property)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [property]&quot;) 
+		
+		if(!attrs.title &amp;&amp; !attrs.titleKey)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [title] or [titleKey]&quot;)
+
+		def property = attrs.remove(&quot;property&quot;)
+		def action = attrs.action ? attrs.remove(&quot;action&quot;) : &quot;list&quot;
+		
+		def defaultOrder = attrs.remove(&quot;defaultOrder&quot;)
+		if(defaultOrder != &quot;desc&quot;) defaultOrder = &quot;asc&quot;
+
+		// current sorting property and order
+		def sort = params.sort
+		def order = params.order
+
+		// add sorting property and params to link params
+		def linkParams = [sort:property]
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		// determine and add sorting order for this column to link params
+		attrs.class = &quot;sortable&quot;
+		if(property == sort) {
+			attrs.class = attrs.class + &quot; sorted &quot; + order
+			if(order == &quot;asc&quot;) {
+				linkParams.order = &quot;desc&quot;
+			}
+			else {
+				linkParams.order = &quot;asc&quot;
+			}
+		}
+		else {
+			linkParams.order = defaultOrder
+		}
+
+		// determine column title
+		def title = attrs.remove(&quot;title&quot;)
+		def titleKey = attrs.remove(&quot;titleKey&quot;)
+		if(titleKey) {
+			if(!title) title = titleKey
+			def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+			def locale = RCU.getLocale(request)
+			title = messageSource.getMessage(titleKey, null, title, locale)
 		}
 
+		out &lt;&lt; &quot;&lt;th &quot;
+		// process remaining attributes
+		attrs.each { k, v -&gt;
+			out &lt;&lt; &quot;${k}=\&quot;${v.encodeAsHTML()}\&quot; &quot;
+		}
+		out &lt;&lt; &quot;&gt;${link(action:action, params:linkParams) { title }}&lt;/th&gt;&quot;
 	}
 
     /**
@@ -199,14 +329,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         def uri = grailsAttributes.getTemplateUri(attrs.template,request)
         def var = attrs['var']
 
-        def url = servletContext.getResource(uri)
-        if(!url)
-            throwTagError(&quot;No template found for name [${attrs.template}] in tag [render]&quot;)
-
-        def t = engine.createTemplate(  uri,
-                                        servletContext,
-                                        request,
-                                        response)
+        def t = engine.createTemplate( uri )
 
         if(attrs.model instanceof Map) {
             t.make( attrs.model ).writeTo(out)
@@ -246,14 +369,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 	        def engine = grailsAttributes.getPagesTemplateEngine()
 	        def uri = grailsAttributes.getTemplateUri(attrs.template,request)
 
-	        def url = servletContext.getResource(uri)
-	        if(!url)
-	            throwTagError(&quot;No template found for name [${attrs.template}] in tag [include]&quot;)
-
-	        def t = engine.createTemplate(  uri,
-	                                        servletContext,
-	                                        request,
-	                                        response)
+	        def t = engine.createTemplate(  uri )
 			
 			t.make().writeTo(out)
 		}</diff>
      <filename>racetrack_ch3/plugins/core/grails-app/taglib/RenderTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -152,7 +152,7 @@ class UITagLib {
 	 * &lt;g:richTextEditor name=&quot;editor&quot; height=&quot;400&quot; /&gt;
 	 */
 	def richTextEditor = { attrs -&gt;
-		withTag(name:'script',attributes:[type:'text/javascript']) {
+		out &lt;&lt; withTag(name:'script',attributes:[type:'text/javascript']) {
 			if(attrs.onComplete) {
 				out.println &quot;function FCKeditor_OnComplete( editorInstance ) {&quot;
 					out.println &quot;${attrs.onComplete}(editorInstance);&quot;					
@@ -162,24 +162,53 @@ class UITagLib {
 			var oFCKeditor = new FCKeditor( '${attrs.name}' ) ;
 			oFCKeditor.BasePath	 = \&quot;&quot;&quot;&quot;
 			if(attrs.basepath) {
-				createLinkTo(dir:attrs.basepath)
+				out &lt;&lt; createLinkTo(dir:attrs.basepath)
 			}
 			else {
-				createLinkTo(dir:&quot;fckeditor/&quot;)
+			    out &lt;&lt; createLinkTo(dir:&quot;fckeditor/&quot;)
 			}
 			out.println '&quot;;'
 			if(attrs.toolbar) {
 				out &lt;&lt; &quot;oFCKeditor.ToolbarSet	 = '${attrs.toolbar}';&quot; 	
-			}			
+			}
+			// add width support
+			if(attrs.width)			
+				out.println &quot;oFCKeditor.Width	= '${attrs.width}';&quot;
+			
 			if(attrs.height)			
-				out.println &quot;oFCKeditor.Height	= ${attrs.height};&quot;
+				out.println &quot;oFCKeditor.Height	= '${attrs.height}';&quot;
+			
+			// add skin support, values to choose: &quot;default&quot;, &quot;office2003&quot;, &quot;silver&quot;
+			if(attrs.skin)
+				out.println &quot;oFCKeditor.Config['SkinPath'] = 'skins/${attrs.skin}/';&quot;
+			
+			// check the browser compatibility when rendering the editor.  default value: true, values to choose: true, false, 
+			if(attrs.checkBrowser)
+				out.println &quot;oFCKeditor.CheckBrowser = ${attrs.checkBrowser};&quot;
+
+			// show error messages on errors while rendering the editor.   default value: true, values to choose: true, false
+			if(attrs.displayErrors)
+				out.println &quot;oFCKeditor.DisplayErrors = ${attrs.displayErrors};&quot;
+
+			// oFCKeditor.Config      AutoDetectLanguage:true/false, DefaultLanguage:'pt-BR' and so on
+			if(attrs.config) {
+				if (attrs.config instanceof Map) {
+					attrs.config.each { k, v -&gt;
+						out.println &quot;oFCKeditor.Config['$k'] = '$v';&quot;
+					}
+				} else {
+					throw new Exception(&quot;&quot;&quot;The format of config is not correct, it should be like &quot;[AutoDetectLanguage:false, DefaultLanguage:'pt-BR']&quot;   &quot;&quot;&quot;)
+				}
+			}
+
 			if(attrs.value) {
 				out &lt;&lt; &quot;oFCKeditor.Value	= \&quot;&quot;
-				escapeJavascript(Collections.EMPTY_MAP,attrs.value)
+			    out &lt;&lt; escapeJavascript(Collections.EMPTY_MAP,attrs.value)
 				out.println &quot;\&quot; ;&quot;
 			}
 			
-			out.println &quot;oFCKeditor.Create();&quot;			
+			out.println &quot;oFCKeditor.Create();&quot;	
+
 		}
 	}
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch3/plugins/core/grails-app/taglib/UITagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -32,9 +32,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def checkList = []
         if(model) {
-            checkList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors))
-            }
+            checkList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             checkList &lt;&lt; attrs['bean']
@@ -45,7 +43,7 @@ class ValidationTagLib {
 					if(ra) {
                         if(ra instanceof Errors)
                             checkList &lt;&lt; ra
-	                    else if ((ra.properties.errors) &amp;&amp; (ra.errors instanceof Errors)) {
+	                    else if (ra.properties?.errors instanceof Errors) {
                             checkList &lt;&lt; ra
 						}
 					}
@@ -55,23 +53,29 @@ class ValidationTagLib {
 
         for(i in checkList) {
             def errors = null
-            if(i instanceof Errors) {
+            if (i instanceof Errors) {
                errors = i
             }
-            else {
-				if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
-	                if (i.hasErrors())
-	                    errors = i.errors
-	            }
+            else {       
+				try {
+					if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
+		                if (i.hasErrors())
+		                    errors = i.errors
+		            }
+					
+				}   
+				catch(MissingPropertyException mpe) {
+					// ignore
+				}
 			}
             if(errors) {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
-                        body()
+                        out &lt;&lt; body()
                     }
                 }
                 else {
-                    body()
+                    out &lt;&lt; body()
                 }
             }
         }
@@ -84,9 +88,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def errorList = []
         if(model) {
-            errorList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors)) 
-            }
+            errorList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             errorList &lt;&lt; attrs['bean']
@@ -95,9 +97,9 @@ class ValidationTagLib {
             request.attributeNames.each {
                 def ra = request[it]
                 if(ra) {
-                    if(ra instanceof Errors)
+                    if (ra instanceof Errors)
                         errorList &lt;&lt; ra
-                    else if ((ra.errors != null) &amp;&amp; (ra.errors instanceof Errors)) {
+                    else if (ra.properties?.errors instanceof Errors) {
                         errorList &lt;&lt; ra
 					}
                 }
@@ -119,13 +121,13 @@ class ValidationTagLib {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
                         errors.getFieldErrors( attrs[&quot;field&quot;] ).each {
-                            body(it)
+                            out &lt;&lt; body(it)
                         }
                     }
                 }
                 else {
                     errors.allErrors.each {
-                        body( it )
+                        out &lt;&lt; body( it )
                     }
                 }
             }
@@ -141,9 +143,9 @@ class ValidationTagLib {
 
         if(renderAs == 'list') {
             out &lt;&lt; &quot;&lt;ul&gt;&quot;
-            eachError(attrs, {
+            out &lt;&lt; eachError(attrs, {
                 out &lt;&lt; &quot;&lt;li&gt;&quot;
-                message(error:it)
+                out &lt;&lt; message(error:it)
                 out &lt;&lt; &quot;&lt;/li&gt;&quot;
               }
             )
@@ -219,7 +221,7 @@ class ValidationTagLib {
         }
 
         def app = grailsAttributes.getGrailsApplication()
-        def dc = app.getGrailsDomainClass(againstClass)
+        def dc = app.getDomainClass(againstClass)
 
         if(!dc)
             throwTagError(&quot;Tag [validate] could not find a domain class to validate against for name [${againstClass}]&quot;)</diff>
      <filename>racetrack_ch3/plugins/core/grails-app/taglib/ValidationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ class URLCodec {
     }
 
     static decode = { obj -&gt;
-        URLEncoder.decode(obj.toString(), URLCodec.getEncoding())
+        URLDecoder.decode(obj.toString(), URLCodec.getEncoding())
     }
 
 	private static def getEncoding() {</diff>
      <filename>racetrack_ch3/plugins/core/grails-app/utils/URLCodec.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch3/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,9 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 
-&lt;beans&gt;
 	&lt;bean id=&quot;grailsApplication&quot; class=&quot;org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean&quot;&gt;
 		&lt;description&gt;Grails application factory bean&lt;/description&gt;
 		&lt;property name=&quot;groovyFiles&quot;&gt;
@@ -25,7 +27,7 @@
         &lt;property name=&quot;pluginManager&quot; ref=&quot;pluginManager&quot; /&gt;
     &lt;/bean&gt;
 	
-    &lt;bean id=&quot;grailsResourceHolder&quot; singleton=&quot;false&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
+    &lt;bean id=&quot;grailsResourceHolder&quot; scope=&quot;prototype&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
         &lt;property name=&quot;resources&quot;&gt;
               &lt;value&gt;classpath*:**/grails-app/**/*.groovy&lt;/value&gt;
         &lt;/property&gt;</diff>
      <filename>racetrack_ch3/web-app/WEB-INF/applicationContext.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch3/web-app/WEB-INF/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,254 @@
     &lt;uri&gt;http://grails.codehaus.org/tags&lt;/uri&gt;
 
     &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var}
+        &lt;/description&gt;
+        &lt;name&gt;set&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovySetTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var} into the page context
+        &lt;/description&gt;
+        &lt;name&gt;def&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyDefTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical if tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;if&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical else tag as fallback if the if condition fails
+        &lt;/description&gt;
+        &lt;name&gt;else&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical elseif tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;elseif&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;
+        	Tag to loop over a collection while the test expression returns true
+        &lt;/description&gt;
+        &lt;name&gt;while&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyWhileTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;each&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyEachTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;findAll&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyFindAllTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to filter the elements to iterate over&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and collects the elements
+        	you want to work with&lt;/description&gt;
+        &lt;name&gt;collect&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyCollectTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to use to collect the elements. The
+        	expression must retur true to add the element to the
+        	collection&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and filters the elements
+        with a regular expression&lt;/description&gt;
+        &lt;name&gt;grep&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyGrepTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The regular expression to filter the element with. The
+        	filter is a simple Groovy Regex&lt;/description&gt;
+            &lt;name&gt;filter&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;A tag that attempts to render an input for a bean property
+        into an appropriate component based on the type. It uses the templates
+        defined in &quot;grails-app/views/scaffolding&quot; to achieve this by looking up
+		the template by type.&lt;/description&gt;
+        &lt;name&gt;renderInput&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyRenderInputTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The Bean to render the input for&lt;/description&gt;
+            &lt;name&gt;bean&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The property of the bean to render input for&lt;/description&gt;
+            &lt;name&gt;property&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
         &lt;name&gt;link&lt;/name&gt;
         &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag&lt;/tag-class&gt;
         &lt;body-content&gt;JSP&lt;/body-content&gt;</diff>
      <filename>racetrack_ch3/web-app/WEB-INF/tld/grails.tld</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
 &lt;web-app version=&quot;2.4&quot;
          xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
          xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</diff>
      <filename>racetrack_ch3/web-app/WEB-INF/web.template.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
+&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;log4jRefreshInterval&lt;/param-name&gt;&lt;param-value&gt;1000&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
 		              Allows developers to view the intermediade source code, when they pass
-		                a spillGroovy argument in the URL.					
-							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file
+		                a spillGroovy argument in the URL.
+							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;*.dispatch&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch3/web-app/WEB-INF/web.xml</filename>
    </modified>
    <modified>
      <diff>@@ -124,4 +124,15 @@ td .errors {
 .prop .value {
 	text-align:left;
 	width:80%;
+}
+
+.prevLink, .step, .currentStep, .nextLink {
+	padding-right: 5px;
+}
+.currentStep {
+	font-weight:bold;
+}
+
+th.sorted a, th.sorted a:link, th.sorted a:visited, th.sorted a:hover, th.sortable a, th.sortable a:link, th.sortable a:visited, th.sortable a:hover {
+	color: white;
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch3/web-app/css/main.css</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,9 @@
 	&lt;classpathentry kind=&quot;src&quot; path=&quot;grails-tests&quot;/&gt;
 	&lt;classpathentry kind=&quot;con&quot; path=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot;/&gt;
 	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/ant/lib/ant.jar&quot;/&gt;
-    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
+    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-junit.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant.jar&quot; /&gt;
 
@@ -48,9 +50,9 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ejb3-persistence.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.2-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.5-SNAPSHOT.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.0.1-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.1-BETA-1.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-starter.jar&quot; /&gt;
 
@@ -80,13 +82,13 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/log4j-1.2.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ognl-2.7.jar&quot; /&gt;
-
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/org.mortbay.jetty.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/oro-2.0.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.5.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.6.0.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/serializer.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/servletapi-2.4.jar&quot; /&gt;
 
@@ -106,18 +108,20 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/standard-2.4.jar&quot; /&gt;
 
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xalan.jar&quot; /&gt;
+
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xerces-2.6.2.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xml-apis.jar&quot; /&gt;
 
 
-	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.4.2.jar&quot; /&gt;
+	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.5.jar&quot; /&gt;
 
 
 	&lt;classpathentry kind=&quot;output&quot; path=&quot;web-app/WEB-INF/classes&quot;/&gt;</diff>
      <filename>racetrack_ch4/.classpath</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-#Do not edit app.grails.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place!
-#Sun Mar 11 15:49:46 EDT 2007
-app.grails.version=0.4.2
+#Wed May 02 20:22:50 EDT 2007
+app.version=0.1
+app.grails.version=0.5
 app.name=racetrack</diff>
      <filename>racetrack_ch4/application.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class DevelopmentDataSource { 
+class DevelopmentDataSource {
    boolean pooling = true 
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_dev&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
    String password = &quot;&quot; 
-} 
+}</diff>
      <filename>racetrack_ch4/grails-app/conf/DevelopmentDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch4/grails-app/conf/log4j.development.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch4/grails-app/conf/log4j.production.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch4/grails-app/conf/log4j.test.properties</filename>
    </modified>
    <modified>
      <diff>@@ -46,8 +46,8 @@ class RaceController {
         def race = Race.get( params.id )
         if(race) {
              race.properties = params
-            if(race.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+            if(race.save()) {       
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:race.id)
             }
             else {
@@ -70,7 +70,7 @@ class RaceController {
         def race = new Race()
         race.properties = params
         if(race.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot; 
             redirect(action:show,id:race.id)
         }
         else {</diff>
      <filename>racetrack_ch4/grails-app/controllers/RaceController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -47,7 +47,7 @@ class RegistrationController {
         if(registration) {
              registration.properties = params
             if(registration.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:registration.id)
             }
             else {
@@ -70,7 +70,7 @@ class RegistrationController {
         def registration = new Registration()
         registration.properties = params
         if(registration.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot;                 
             redirect(action:show,id:registration.id)
         }
         else {</diff>
      <filename>racetrack_ch4/grails-app/controllers/RegistrationController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Race {  
+class Race { 
     String name 
     Date startDateTime 
     String city 
@@ -7,16 +7,16 @@ class Race {
     Float cost 
     Integer maxRunners = 100000 
      
-    static hasMany = [registrations:Registration]  
+    static hasMany = [registrations:Registration]
     
     static constraints = { 
-        name(maxLength:50,blank:false) 
-        startDateTime(validator: {return (it &gt; new Date())})  
-        city(maxLength:30,blank:false) 
+        name(maxSize:50,blank:false) 
+        startDateTime(validator: {return (it &gt; new Date())}) 
+        city(maxSize:30,blank:false) 
         state(inList:['GA', 'NC', 'SC', 'VA'],blank:false) 
         distance(min:3.1f,max:100f) 
         cost(min:0f,max:999.99f) 
-    }
+    } 
     
-    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot;}     
-}
\ No newline at end of file
+    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot; }
+}	</diff>
      <filename>racetrack_ch4/grails-app/domain/Race.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Registration  {  
+class Registration { 
     Race race 
     String name 
     Date dateOfBirth 
@@ -6,19 +6,17 @@ class Registration  {
     String postalAddress 
     String emailAddress 
     Date createdAt = new Date() 
-    
+
     static belongsTo = Race 
-    
-    static optionals = [&quot;postalAddress&quot; ]  
-    
+
     static constraints = { 
-        name(maxLength:50,blank:false) 
+        name(maxSize:50,blank:false) 
         dateOfBirth(nullable:false) 
         gender(inList:[&quot;M&quot;, &quot;F&quot;]) 
-        postalAddress(maxLength:255) 
-        emailAddress(maxLength:50,email:true) 
+        postalAddress(nullable:true,maxSize:255) 
+        emailAddress(maxSize:50,email:true) 
         race(nullable:false) 
     } 
-
-  String toString() {&quot;${this.name} : ${this.emailAddress}&quot;}         
-}
\ No newline at end of file
+    
+    String toString(){&quot;${this.name}:${this.emailAddress}&quot;}         
+}	</diff>
      <filename>racetrack_ch4/grails-app/domain/Registration.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,29 +1,28 @@
 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.message=Property [{0}] of class [{1}] is not a valid [{2}].
+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.length.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
-default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
 default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
-default.invalid.max.length.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
-default.invalid.min.length.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{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.not.editable.message=Property [{0}] of class [{1}] with value [{2}] cannot be changed from [{3}] 
 
-race.name.blank=Please enter a name for this race 
+default.paginate.prev=Previous
+default.paginate.next=Next
+
+race.name.blank=Please enter a name for this race
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles 
 race.startDateTime.validator.invalid=Please enter a future date and time
 race.city.blank=Please enter a city for this race
-race.city.maxLength.exceeded=Please limit the city name to a maximum length of {3} characters
+race.city.maxSize.exceeded=Please limit the city name to a maximum length of {3} characters
 race.distance.nullable=Please enter a valid distance
 race.distance.min.notmet=Please enter a valid distance no fewer than {3} miles
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles
@@ -32,8 +31,8 @@ race.cost.min.notmet=Please enter a valid cost of at least ${3}
 race.cost.max.exceeded=Please enter a valid cost no more than ${3}
 
 registration.name.blank=Please enter a name
-registration.name.maxLength.exceeded=Please limit the name to a maximum length of {3} characters
-registration.postalAddress.maxLength.exceeded=Please limit the postal address to a maximum length of {3} characters
+registration.name.maxSize.exceeded=Please limit the name to a maximum length of {3} characters
+registration.postalAddress.maxSize.exceeded=Please limit the postal address to a maximum length of {3} characters
 registration.emailAddress.blank=Please enter an e-mail address
-registration.emailAddress.maxLength.exceeded=Please limit the e-mail address to a maximum length of {3} characters
+registration.emailAddress.maxSize.exceeded=Please limit the e-mail address to a maximum length of {3} characters
 registration.emailAddress.email.invalid=Please enter a valid e-mail address
\ No newline at end of file</diff>
      <filename>racetrack_ch4/grails-app/i18n/messages.properties</filename>
    </modified>
    <modified>
      <diff>@@ -27,19 +27,19 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/race/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -30,19 +30,19 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='registrations'&gt;Registrations:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'registrations','errors')}'&gt;&lt;ul&gt;
     &lt;g:each var='r' in='${race?.registrations?}'&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/race/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -20,17 +20,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Start Date Time&lt;/th&gt;
-                                      
-                        &lt;th&gt;City&lt;/th&gt;
-                                      
-                        &lt;th&gt;State&lt;/th&gt;
-                                      
-                        &lt;th&gt;Distance&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;startDateTime&quot; title=&quot;Start Date Time&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;city&quot; title=&quot;City&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;state&quot; title=&quot;State&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;distance&quot; title=&quot;Distance&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/race/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
   
 &lt;html&gt;
     &lt;head&gt;
-         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
+         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;  
          &lt;g:javascript library=&quot;racetrack&quot; /&gt;          
           &lt;meta name=&quot;layout&quot; content=&quot;main&quot; /&gt;
          &lt;title&gt;Show Race&lt;/title&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/race/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -27,7 +27,7 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -35,12 +35,10 @@
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='createdAt'&gt;Created At:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'createdAt','errors')}'&gt;&lt;g:datePicker name='createdAt' value=&quot;${registration?.createdAt}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
-                       
                     &lt;/tbody&gt;
                &lt;/table&gt;
                &lt;/div&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/registration/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -30,7 +30,7 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -38,7 +38,7 @@
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -50,7 +50,7 @@
 
                &lt;div class=&quot;buttons&quot;&gt;
                      &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Update&quot; /&gt;&lt;/span&gt;
-                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/div&gt;
             &lt;/g:form&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/registration/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -20,17 +20,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Date Of Birth&lt;/th&gt;
-                                      
-                        &lt;th&gt;Gender&lt;/th&gt;
-                                      
-                        &lt;th&gt;Postal Address&lt;/th&gt;
-                                      
-                        &lt;th&gt;Email Address&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;dateOfBirth&quot; title=&quot;Date Of Birth&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;gender&quot; title=&quot;Gender&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;postalAddress&quot; title=&quot;Postal Address&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;emailAddress&quot; title=&quot;Email Address&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/registration/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -77,7 +77,7 @@
                &lt;g:form controller=&quot;registration&quot;&gt;
                  &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;${registration?.id}&quot; /&gt;
                  &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Edit&quot; /&gt;&lt;/span&gt;
-                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/g:form&gt;
            &lt;/div&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch4/grails-app/views/registration/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,10 @@ import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
-class ApplicationTagLib {
+class ApplicationTagLib { 
+	
+	def grailsUrlMappingsHolder
+	
     /**
      * Creates a link to a resource, generally used as a method rather than a tag.
      *
@@ -33,7 +36,7 @@ class ApplicationTagLib {
      */
     def createLinkTo = { attrs -&gt;
          out &lt;&lt; grailsAttributes.getApplicationUri(request)
-         if(attrs['dir']) {
+         if(attrs['dir'] || attrs['dir'] == '') {
             out &lt;&lt; &quot;/${attrs['dir']}&quot;
          }
          if(attrs['file']) {
@@ -50,7 +53,7 @@ class ApplicationTagLib {
     def link = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;a href=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // process remaining attributes
@@ -59,7 +62,7 @@ class ApplicationTagLib {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -79,29 +82,47 @@ class ApplicationTagLib {
         if(attrs['url']) {
              attrs = attrs.remove('url')
         }
-        // if the current attribute null set the controller uri to the current controller
-        if(attrs[&quot;controller&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;controller&quot;)
-        }
-        else {
-           out &lt;&lt; grailsAttributes.getControllerUri(request)
-        }
-        if(attrs[&quot;action&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;action&quot;)
-        }
-        if(attrs[&quot;id&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;id&quot;)
-        }
-        if(attrs['params']) {
-            def pms = attrs.remove('params')
-            out &lt;&lt; '?'
-            def i = 0
-            pms.each { k,v -&gt;
-                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
-                if(++i &lt; pms.size())
-                   out &lt;&lt; '&amp;'
-            }
-        }
+                                                     
+		def controller = attrs.containsKey(&quot;controller&quot;) ? attrs.remove(&quot;controller&quot;) : grailsAttributes.getController(request).controllerName
+		def action = attrs.remove(&quot;action&quot;)
+        def id = attrs.remove(&quot;id&quot;)
+        def params = attrs.params ? attrs.remove('params') : [:]
+
+        def url
+		try {
+            if(id) params.id = id
+            def mapping = grailsUrlMappingsHolder?.getReverseMapping(controller,action,params)
+			params.controller = controller
+			if(action) params.action = action  
+            url = mapping?.createURL(params)
+		}        
+		finally {
+			params.remove('controller')
+			params.remove('action')          
+			params.remove('id')
+		}
+		if(url) {
+			out &lt;&lt; url
+		}             
+		else {
+            out &lt;&lt; '/' &lt;&lt; controller
+	        if(action) {
+	            out &lt;&lt; '/' &lt;&lt; action
+	        }
+	        if(id) {
+	            out &lt;&lt; '/' &lt;&lt; id
+	        }
+	        if(params) {
+	            out &lt;&lt; '?'
+	            def i = 0
+	            params.each { k,v -&gt;
+	                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
+	                if(++i &lt; params.size())
+	                   out &lt;&lt; '&amp;'
+	            }
+	        }			
+		}
+															
     }
 
 	/**
@@ -127,8 +148,8 @@ class ApplicationTagLib {
 				} 				
 			}
 		}
-		out &lt;&lt; '&gt;'
-		body()
+		out &lt;&lt; '&gt;'  
+		out &lt;&lt; body()
 		out &lt;&lt; &quot;&lt;/${attrs.name}&gt;&quot;			
 	}	
 }</diff>
      <filename>racetrack_ch4/plugins/core/grails-app/taglib/ApplicationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -16,6 +16,7 @@ import org.springframework.validation.Errors;
 import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
+import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
 
  /**
  *  A  tag lib that provides tags for working with form controls
@@ -33,7 +34,10 @@ class FormTagLib {
 	def textField = { attrs -&gt;
 		attrs.type = &quot;text&quot;  
 		attrs.tagName = &quot;textField&quot; 
-		field(attrs)
+		def result = field(attrs)
+		if(result) {     
+			out &lt;&lt; result
+		}
 	}
 	/**
 	 * Creates a hidden field
@@ -41,7 +45,7 @@ class FormTagLib {
 	def hiddenField = { attrs -&gt;
 		attrs.type = &quot;hidden&quot;
 		attrs.tagName = &quot;hiddenField&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * Creates a submit button
@@ -49,7 +53,7 @@ class FormTagLib {
 	def submitButton = { attrs -&gt;
 		attrs.type = &quot;submit&quot;
 		attrs.tagName = &quot;submitButton&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * A general tag for creating fields
@@ -84,7 +88,7 @@ class FormTagLib {
     void resolveAttributes(attrs)
     {
         if(!attrs.name &amp;&amp; !attrs.field) {
-            throwTagError(&quot;Tag [$tagName] is missing required attribute [name] or [field]&quot;)
+            throwTagError(&quot;Tag [${attrs.tagName}] is missing required attribute [name] or [field]&quot;)
         }
         attrs.remove('tagName')
 
@@ -121,7 +125,7 @@ class FormTagLib {
     def form = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;form action=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // default to post
@@ -133,26 +137,34 @@ class FormTagLib {
 
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        def bodyContent = body()
+		out &lt;&lt; bodyContent
 
         // close tag
         out &lt;&lt; &quot;&lt;/form&gt;&quot;
     }
     /**
      * Creates a submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmit value=&quot;Edit&quot; /&gt;
+     *  &lt;g:actionSubmit action=&quot;Edit&quot; value=&quot;Some label for editing&quot; /&gt;
      *
      */
     def actionSubmit = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;submit&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+    	if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
-        // process remaining attributes
+
+		// add action and value
+		def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    	
+    	out &lt;&lt; &quot;&lt;input type=\&quot;submit\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+    	
+    	// process remaining attributes
         outputAttributes(attrs)
 
         // close tag
@@ -161,22 +173,30 @@ class FormTagLib {
     }
     /**
      * Creates a an image submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmitImage src=&quot;/images/submitButton.gif&quot; action=&quot;Edit&quot; /&gt;
      *
      */
     def actionSubmitImage = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;image&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+        if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
+        
+        // add action and value
+        def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    
+        out &lt;&lt; &quot;&lt;input type=\&quot;image\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+
+		// add image src        
         def src = attrs.remove('src')
         if(src) {
              out &lt;&lt; &quot;src=\&quot;${src}\&quot; &quot;
         }
+
         // process remaining attributes
         outputAttributes(attrs)
 
@@ -201,6 +221,8 @@ class FormTagLib {
 
         def value = (attrs['value'] ? attrs['value'] : xdefault)
         def name = attrs['name']
+        def id = attrs['id'] ? attrs['id'] : name
+
 		def noSelection = attrs['noSelection']
 		if (noSelection != null)
 		{
@@ -253,7 +275,7 @@ class FormTagLib {
 
         // create day select
         if (precision &gt;= PRECISION_RANKINGS[&quot;day&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_day\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_day\&quot; id=\&quot;${id}_day\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -272,7 +294,7 @@ class FormTagLib {
 
         // create month select
         if (precision &gt;= PRECISION_RANKINGS[&quot;month&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_month\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_month\&quot; id=\&quot;${id}_month\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -294,7 +316,7 @@ class FormTagLib {
 
         // create year select
         if (precision &gt;= PRECISION_RANKINGS[&quot;year&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_year\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_year\&quot; id=\&quot;${id}_year\&quot;&gt;&quot;
 
             if (noSelection) {
     			renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -313,7 +335,7 @@ class FormTagLib {
 
         // do hour select
         if (precision &gt;= PRECISION_RANKINGS[&quot;hour&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot; id=\&quot;${id}_hour\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -338,7 +360,7 @@ class FormTagLib {
 
         // do minute select
         if (precision &gt;= PRECISION_RANKINGS[&quot;minute&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot; id=\&quot;${id}_minute\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -360,7 +382,7 @@ class FormTagLib {
 	def renderNoSelectionOption = { noSelectionKey, noSelectionValue, value -&gt;
 		// If a label for the '--Please choose--' first item is supplied, write it out
         out &lt;&lt; '&lt;option value=&quot;' &lt;&lt; (noSelectionKey == null ? &quot;&quot; : noSelectionKey) &lt;&lt; '&quot;'
-        if(noSelectionKey == value) {
+        if(noSelectionKey.equals(value)) {
             out &lt;&lt; ' selected=&quot;selected&quot; '
         }
         out &lt;&lt; '&gt;' &lt;&lt; noSelectionValue.encodeAsHTML() &lt;&lt; '&lt;/option&gt;'
@@ -388,7 +410,7 @@ class FormTagLib {
         }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -405,7 +427,7 @@ class FormTagLib {
         attrs['optionValue'] = { &quot;${it.language}, ${it.country},  ${it.displayName}&quot; }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -425,7 +447,7 @@ class FormTagLib {
 		   	attrs.value = null
 		}
         // invoke generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -436,11 +458,15 @@ class FormTagLib {
      * &lt;g:select name=&quot;user.company.id&quot; from=&quot;${Company.list()}&quot; value=&quot;${user?.company.id}&quot; optionKey=&quot;id&quot; /&gt;
      */
     def select = { attrs -&gt;
+	    def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request)
+
         def from = attrs.remove('from')
         def keys = attrs.remove('keys')
         def optionKey = attrs.remove('optionKey')
         def optionValue = attrs.remove('optionValue')
         def value = attrs.remove('value')
+        def valueMessagePrefix = attrs.remove('valueMessagePrefix')
 		def noSelection = attrs.remove('noSelection')
         if (noSelection != null) {
             noSelection = noSelection.entrySet().iterator().next()
@@ -461,20 +487,21 @@ class FormTagLib {
         // create options from list
         if(from) {
             from.eachWithIndex { el,i -&gt;
+            	def keyValue = null
                 out &lt;&lt; '&lt;option '
                 if(keys) {
-                    out &lt;&lt; 'value=&quot;' &lt;&lt; keys[i] &lt;&lt; '&quot; '
-                    if(keys[i] == value) {
+                    keyValue = keys[i]
+                    out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
-               else if(optionKey) {
-                    def keyValue = null
+                else if(optionKey) {
                     if(optionKey instanceof Closure) {
                         keyValue = optionKey(el)
-                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                        out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
-                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getGrailsDomainClass(el.getClass().name)) {
+                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, el.getClass().name)) {
                         keyValue = el.ident()
                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
@@ -488,8 +515,9 @@ class FormTagLib {
                     }
                 }
                 else {
-                    out &lt;&lt; &quot;value=\&quot;${el}\&quot; &quot;
-                    if(el == value) {
+                	keyValue = el
+                    out &lt;&lt; &quot;value=\&quot;${keyValue}\&quot; &quot;
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
@@ -502,6 +530,19 @@ class FormTagLib {
                         out &lt;&lt; el.properties[optionValue].toString().encodeAsHTML()
                     }
                 }
+                else if(valueMessagePrefix) {
+                	def message = messageSource.getMessage(&quot;${valueMessagePrefix}.${keyValue}&quot;, null, null, locale)
+                	if(message) {
+                		out &lt;&lt; message.encodeAsHTML()
+                	}
+                	else if (keyValue) {
+                		out &lt;&lt; keyValue.encodeAsHTML()
+                	}
+					else {
+        	            def s = el.toString()
+    	                if(s) out &lt;&lt; s.encodeAsHTML()
+	                }
+                }
                 else {
                     def s = el.toString()
                     if(s) out &lt;&lt; s.encodeAsHTML()
@@ -554,6 +595,6 @@ class FormTagLib {
         outputAttributes(attrs)
 
         // close the tag, with no body
-        out &lt;&lt; ' &gt;&lt;/input&gt;'
+        out &lt;&lt; ' /&gt;'
      }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch4/plugins/core/grails-app/taglib/FormTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ class JavascriptTagLib  {
 		}
 		else {
 			out.println '&lt;script type=&quot;text/javascript&quot;&gt;'
-				body()
+				out &lt;&lt; body()
 			out.println '&lt;/script&gt;'
 		}
 	}
@@ -137,15 +137,15 @@ class JavascriptTagLib  {
     /**
      * A link to a remote uri that used the prototype library to invoke the link via ajax
      */
-    def remoteLink = { attrs, body -&gt;
+    def remoteLink = { attrs, body -&gt;  
        out &lt;&lt; &quot;&lt;a href=\&quot;&quot;    
 
        def cloned = deepClone(attrs)
-	   createLink(cloned)               
+	   out &lt;&lt; createLink(cloned)               
 
 	   out &lt;&lt; &quot;\&quot; onclick=\&quot;&quot;
         // create remote function
-        remoteFunction(attrs)   
+        out &lt;&lt; remoteFunction(attrs)   
 		attrs.remove('url')
         out &lt;&lt; &quot;return false;\&quot; &quot;
         // process remaining attributes
@@ -154,7 +154,7 @@ class JavascriptTagLib  {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -180,7 +180,7 @@ class JavascriptTagLib  {
 		else {
     		attrs.params = &quot;'${paramName}='+this.value&quot;			
 		}
-		remoteFunction(attrs)
+		out &lt;&lt; remoteFunction(attrs)
 		attrs.remove('params')
 		out &lt;&lt; &quot;\&quot;&quot;   
 		attrs.remove('url')
@@ -208,16 +208,16 @@ class JavascriptTagLib  {
 		// prepare form settings
 		prepareAjaxForm(p,attrs)
         
-        def params = [  onsubmit:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onsubmit:remoteFunction(attrs) + 'return false',
 					    method: (attrs.method? attrs.method : 'POST' ),
-					    action: (attrs.action? attrs.action : TagLibUtil.outToString(createLink,url))		                 
+					    action: (attrs.action? attrs.action : createLink(url))		                 
 		             ]
 		attrs.remove('url')		             
 	    params.putAll(attrs)
 		if(params.name &amp;&amp; !params.id)
 			params.id = params.name
-	    withTag(name:'form',attrs:params) {
-			body()   
+	    out &lt;&lt; withTag(name:'form',attrs:params) {
+			out &lt;&lt; body()   
 	    }		
     }
 
@@ -230,7 +230,7 @@ class JavascriptTagLib  {
 		// prepare form settings 
 		attrs.forSubmitTag = &quot;.form&quot;
 		prepareAjaxForm(p,attrs)    
-        def params = [  onclick:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onclick:remoteFunction(attrs) + 'return false',
 					    type: 'button',
 					    name: attrs.remove('name'),
 					    value: attrs.remove('value'), 
@@ -238,8 +238,8 @@ class JavascriptTagLib  {
 					    'class':attrs.remove('class')
 		             ]
 		             
-		withTag(name:'input', attrs:params) {
-			body()	
+		out &lt;&lt; withTag(name:'input', attrs:params) {
+			out &lt;&lt; body()	
 		}
     }
 	
@@ -275,7 +275,7 @@ class JavascriptTagLib  {
 			def sw = new StringWriter()
 			out = new PrintWriter(out)
 			// invoke body
-			body()
+			out &lt;&lt; body()
 			// restore out
 			out = tmp
 			js = sw.toString()
@@ -357,10 +357,10 @@ class PrototypeProvider implements JavascriptProvider {
 		
 		def pms = attrs.remove('params')   
 		if(attrs.url) {
-			taglib.createLink(attrs.url)			
+			out &lt;&lt; taglib.createLink(attrs.url)			
 		}                              
 		else {
-			taglib.createLink(attrs)			
+			out &lt;&lt; taglib.createLink(attrs)			
 		}
 
 		
@@ -415,6 +415,7 @@ class PrototypeProvider implements JavascriptProvider {
 	                    case 'true': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case 'false': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case ~/\s*function(\w*)\s*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
+	                    case ~/Insertion\..*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    default:ajaxOptions &lt;&lt; &quot;${k}:'${v}'&quot;; break;
 	                 }            	
             	}
@@ -441,10 +442,10 @@ class YahooProvider implements JavascriptProvider {
 		out &lt;&lt; &quot;YAHOO.util.Connect.asyncRequest('${method}','&quot;
 				
 		if(attrs.url) {
-			taglib.createLink(attrs.url)
+			out &lt;&lt; taglib.createLink(attrs.url)
 		}
 		else {
-			taglib.createLink(attrs)
+			out &lt;&lt; taglib.createLink(attrs)
 		}		
 		attrs.remove('url')
 		out &lt;&lt; &quot;',&quot;
@@ -504,7 +505,7 @@ class DojoProvider implements JavascriptProvider {
 		}		
 		 out &lt;&lt; 'dojo.io.bind({url:\''
 
-		 taglib.createLink(attrs) 
+		 out &lt;&lt; taglib.createLink(attrs) 
 		attrs.remove('params')
 		 out &lt;&lt; '\',load:function(type,data,evt) {'
 	    if(attrs.onLoaded) {</diff>
      <filename>racetrack_ch4/plugins/core/grails-app/taglib/JavascriptTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,6 +25,7 @@ import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
 class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants {
+	def out // to facilitate testing
 
     protected getPage() {
     	return request[PAGE]
@@ -91,7 +92,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 				}
 			}
 			if(invokeBody) {
-				body();	
+				out &lt;&lt; body()
 			}
 		}
 	}
@@ -134,54 +135,183 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         if(attrs.total == null)
             throwTagError(&quot;Tag [paginate] is missing required attribute [total]&quot;)
 		
-		def mkp = new groovy.xml.MarkupBuilder(out)
+		def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request) 
+		
 		def total = attrs.total.toInteger()
-		def max = params.max?.toInteger()
-		def offset = params.offset?.toInteger() 
 		def action = (attrs.action? attrs.action : 'list')
-		def breadcrumb = true
-		if(attrs.breadcrumb) breadcrumb = Boolean.valueOf(attrs.breadcrumb)
-			
+		def offset = params.offset?.toInteger()
+		def max = params.max?.toInteger()
+		def maxsteps = (attrs.maxsteps ? attrs.maxsteps.toInteger() : 10)
+
+        if(attrs.breadcrumb) {
+			log.warn(&quot;Tag [paginate] includes the [breadcrumb] attribute. This attribute is deprecated and will be removed in the future. Please update your code to use the [maxsteps] attribute instead.&quot;)
+		}
+
+		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)			
 		if(!max) max = (attrs.max ? attrs.max.toInteger() : 10)
-		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)
 		
-		def linkParams = [offset:offset-max,max:max]
-		def linkTagAttrs = ['class':'prevLink',action:action]
+		def linkParams = [offset:offset - max, max:max]
+		if(params.sort) linkParams.sort = params.sort
+		if(params.order) linkParams.order = params.order
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		def linkTagAttrs = [action:action]
 		if(attrs.controller) {
 			linkTagAttrs.controller = attrs.controller	
 		}
 		if(attrs.id) {
 			linkTagAttrs.id = attrs.id	
 		}
-		if(attrs.params)linkParams.putAll(attrs.params)
 		linkTagAttrs.params = linkParams
-	
-		def combined = max + offset
-		if(offset &gt; 0) {			
-			link(linkTagAttrs.clone(),{out&lt;&lt; (attrs.prev? attrs.prev : 'Previous' ) })
+		
+		// determine paging variables
+		def steps = maxsteps &gt; 0
+		int currentstep = (offset / max) + 1
+		int firststep = 1
+		int laststep = Math.round(Math.ceil(total / max))
+			
+		// display previous link when not on firststep
+		if(currentstep &gt; firststep) {
+			linkTagAttrs.class = 'prevLink'
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.prev ? attrs.prev : messageSource.getMessage('default.paginate.prev', null, 'Previous', locale))
+			 }
 		}
 		
-		if(total &gt; max) {
-			linkTagAttrs.'class' = 'step'
-			if(breadcrumb) {
-				def j = 0
-				0.step(total,max) { i -&gt;
-					if(offset == i) {
-						mkp.a('class':'step',&quot;${++j}&quot;)	
-					}
-					else {
-						linkParams.offset=i
-						link(linkTagAttrs.clone(),{out&lt;&lt;++j})	
-					}
-				}			
+		// display steps when steps are enabled and laststep is not firststep
+		if(steps &amp;&amp; laststep &gt; firststep) {
+			linkTagAttrs.class = 'step'
+
+			// determine begin and endstep paging variables
+			int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
+			int endstep = currentstep + Math.round(maxsteps / 2) - 1
+			
+			if(beginstep &lt; firststep) {
+				beginstep = firststep
+				endstep = maxsteps
+			}
+			if(endstep &gt; laststep) {
+				beginstep = laststep - maxsteps + 1
+				if(beginstep &lt; firststep) {
+					beginstep = firststep
+				}
+				endstep = laststep
+			}
+
+			// display firststep link when beginstep is not firststep
+			if(beginstep &gt; firststep) {
+				linkParams.offset = 0
+				out &lt;&lt; link(linkTagAttrs.clone()) {firststep.toString()}
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+			}
+
+			// display paginate steps
+			(beginstep..endstep).each { i -&gt;
+				if(currentstep == i) {
+					out &lt;&lt; &quot;&lt;span class=\&quot;currentStep\&quot;&gt;${i}&lt;/span&gt;&quot;
+				}
+				else {
+					linkParams.offset = (i - 1) * max
+					out &lt;&lt; link(linkTagAttrs.clone()) {i.toString()}
+				}
+			}	
+			
+			// display laststep link when endstep is not laststep
+			if(endstep &lt; laststep) {
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+				linkParams.offset = (laststep -1) * max
+				out &lt;&lt; link(linkTagAttrs.clone()) { laststep.toString() }
+			}		
+		}
+		
+		// display next link when not on laststep
+		if(currentstep &lt; laststep) {	
+			linkTagAttrs.class = 'nextLink'			
+			linkParams.offset = offset + max
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.next ? attrs.next : messageSource.getMessage('default.paginate.next', null, 'Next', locale))
 			}			
 		}
-		linkParams.offset = offset+max
-		if(combined &lt; total) {	
-			linkTagAttrs.'class'='nextLink'			
-			link(linkTagAttrs,{out&lt;&lt; (attrs.'next'? attrs.'next' : 'Next' )})			
+
+	}
+
+	/**
+	 * Renders a sortable column to support sorting in list views
+	 *
+	 * Attributes:
+	 *
+	 * property - name of the property relating to the field
+	 * defaultOrder (optional) - default order for the property; choose between asc (default if not provided) and desc
+	 * title (optional*) - title caption for the column
+	 * titleKey (optional*) - title key to use for the column, resolved against the message source
+	 * params (optional) - a map containing request parameters
+	 *
+	 * Attribute title or titleKey is required. When both attributes are specified then titleKey takes precedence,
+	 * resulting in the title caption to be resolved against the message source. In case when the message could
+	 * not be resolved, the title will be used as title caption. 
+	 *
+	 * Examples:
+	 *
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; style=&quot;width: 200px&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; titleKey=&quot;book.title&quot; /&gt;	 
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; titleKey=&quot;book.releaseDate&quot; /&gt;
+	 */
+	def sortableColumn = { attrs -&gt;
+
+		if(!attrs.property)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [property]&quot;) 
+		
+		if(!attrs.title &amp;&amp; !attrs.titleKey)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [title] or [titleKey]&quot;)
+
+		def property = attrs.remove(&quot;property&quot;)
+		def action = attrs.action ? attrs.remove(&quot;action&quot;) : &quot;list&quot;
+		
+		def defaultOrder = attrs.remove(&quot;defaultOrder&quot;)
+		if(defaultOrder != &quot;desc&quot;) defaultOrder = &quot;asc&quot;
+
+		// current sorting property and order
+		def sort = params.sort
+		def order = params.order
+
+		// add sorting property and params to link params
+		def linkParams = [sort:property]
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		// determine and add sorting order for this column to link params
+		attrs.class = &quot;sortable&quot;
+		if(property == sort) {
+			attrs.class = attrs.class + &quot; sorted &quot; + order
+			if(order == &quot;asc&quot;) {
+				linkParams.order = &quot;desc&quot;
+			}
+			else {
+				linkParams.order = &quot;asc&quot;
+			}
+		}
+		else {
+			linkParams.order = defaultOrder
+		}
+
+		// determine column title
+		def title = attrs.remove(&quot;title&quot;)
+		def titleKey = attrs.remove(&quot;titleKey&quot;)
+		if(titleKey) {
+			if(!title) title = titleKey
+			def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+			def locale = RCU.getLocale(request)
+			title = messageSource.getMessage(titleKey, null, title, locale)
 		}
 
+		out &lt;&lt; &quot;&lt;th &quot;
+		// process remaining attributes
+		attrs.each { k, v -&gt;
+			out &lt;&lt; &quot;${k}=\&quot;${v.encodeAsHTML()}\&quot; &quot;
+		}
+		out &lt;&lt; &quot;&gt;${link(action:action, params:linkParams) { title }}&lt;/th&gt;&quot;
 	}
 
     /**
@@ -199,14 +329,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         def uri = grailsAttributes.getTemplateUri(attrs.template,request)
         def var = attrs['var']
 
-        def url = servletContext.getResource(uri)
-        if(!url)
-            throwTagError(&quot;No template found for name [${attrs.template}] in tag [render]&quot;)
-
-        def t = engine.createTemplate(  uri,
-                                        servletContext,
-                                        request,
-                                        response)
+        def t = engine.createTemplate( uri )
 
         if(attrs.model instanceof Map) {
             t.make( attrs.model ).writeTo(out)
@@ -246,14 +369,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 	        def engine = grailsAttributes.getPagesTemplateEngine()
 	        def uri = grailsAttributes.getTemplateUri(attrs.template,request)
 
-	        def url = servletContext.getResource(uri)
-	        if(!url)
-	            throwTagError(&quot;No template found for name [${attrs.template}] in tag [include]&quot;)
-
-	        def t = engine.createTemplate(  uri,
-	                                        servletContext,
-	                                        request,
-	                                        response)
+	        def t = engine.createTemplate(  uri )
 			
 			t.make().writeTo(out)
 		}</diff>
      <filename>racetrack_ch4/plugins/core/grails-app/taglib/RenderTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -152,7 +152,7 @@ class UITagLib {
 	 * &lt;g:richTextEditor name=&quot;editor&quot; height=&quot;400&quot; /&gt;
 	 */
 	def richTextEditor = { attrs -&gt;
-		withTag(name:'script',attributes:[type:'text/javascript']) {
+		out &lt;&lt; withTag(name:'script',attributes:[type:'text/javascript']) {
 			if(attrs.onComplete) {
 				out.println &quot;function FCKeditor_OnComplete( editorInstance ) {&quot;
 					out.println &quot;${attrs.onComplete}(editorInstance);&quot;					
@@ -162,24 +162,53 @@ class UITagLib {
 			var oFCKeditor = new FCKeditor( '${attrs.name}' ) ;
 			oFCKeditor.BasePath	 = \&quot;&quot;&quot;&quot;
 			if(attrs.basepath) {
-				createLinkTo(dir:attrs.basepath)
+				out &lt;&lt; createLinkTo(dir:attrs.basepath)
 			}
 			else {
-				createLinkTo(dir:&quot;fckeditor/&quot;)
+			    out &lt;&lt; createLinkTo(dir:&quot;fckeditor/&quot;)
 			}
 			out.println '&quot;;'
 			if(attrs.toolbar) {
 				out &lt;&lt; &quot;oFCKeditor.ToolbarSet	 = '${attrs.toolbar}';&quot; 	
-			}			
+			}
+			// add width support
+			if(attrs.width)			
+				out.println &quot;oFCKeditor.Width	= '${attrs.width}';&quot;
+			
 			if(attrs.height)			
-				out.println &quot;oFCKeditor.Height	= ${attrs.height};&quot;
+				out.println &quot;oFCKeditor.Height	= '${attrs.height}';&quot;
+			
+			// add skin support, values to choose: &quot;default&quot;, &quot;office2003&quot;, &quot;silver&quot;
+			if(attrs.skin)
+				out.println &quot;oFCKeditor.Config['SkinPath'] = 'skins/${attrs.skin}/';&quot;
+			
+			// check the browser compatibility when rendering the editor.  default value: true, values to choose: true, false, 
+			if(attrs.checkBrowser)
+				out.println &quot;oFCKeditor.CheckBrowser = ${attrs.checkBrowser};&quot;
+
+			// show error messages on errors while rendering the editor.   default value: true, values to choose: true, false
+			if(attrs.displayErrors)
+				out.println &quot;oFCKeditor.DisplayErrors = ${attrs.displayErrors};&quot;
+
+			// oFCKeditor.Config      AutoDetectLanguage:true/false, DefaultLanguage:'pt-BR' and so on
+			if(attrs.config) {
+				if (attrs.config instanceof Map) {
+					attrs.config.each { k, v -&gt;
+						out.println &quot;oFCKeditor.Config['$k'] = '$v';&quot;
+					}
+				} else {
+					throw new Exception(&quot;&quot;&quot;The format of config is not correct, it should be like &quot;[AutoDetectLanguage:false, DefaultLanguage:'pt-BR']&quot;   &quot;&quot;&quot;)
+				}
+			}
+
 			if(attrs.value) {
 				out &lt;&lt; &quot;oFCKeditor.Value	= \&quot;&quot;
-				escapeJavascript(Collections.EMPTY_MAP,attrs.value)
+			    out &lt;&lt; escapeJavascript(Collections.EMPTY_MAP,attrs.value)
 				out.println &quot;\&quot; ;&quot;
 			}
 			
-			out.println &quot;oFCKeditor.Create();&quot;			
+			out.println &quot;oFCKeditor.Create();&quot;	
+
 		}
 	}
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch4/plugins/core/grails-app/taglib/UITagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -32,9 +32,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def checkList = []
         if(model) {
-            checkList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors))
-            }
+            checkList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             checkList &lt;&lt; attrs['bean']
@@ -45,7 +43,7 @@ class ValidationTagLib {
 					if(ra) {
                         if(ra instanceof Errors)
                             checkList &lt;&lt; ra
-	                    else if ((ra.properties.errors) &amp;&amp; (ra.errors instanceof Errors)) {
+	                    else if (ra.properties?.errors instanceof Errors) {
                             checkList &lt;&lt; ra
 						}
 					}
@@ -55,23 +53,29 @@ class ValidationTagLib {
 
         for(i in checkList) {
             def errors = null
-            if(i instanceof Errors) {
+            if (i instanceof Errors) {
                errors = i
             }
-            else {
-				if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
-	                if (i.hasErrors())
-	                    errors = i.errors
-	            }
+            else {       
+				try {
+					if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
+		                if (i.hasErrors())
+		                    errors = i.errors
+		            }
+					
+				}   
+				catch(MissingPropertyException mpe) {
+					// ignore
+				}
 			}
             if(errors) {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
-                        body()
+                        out &lt;&lt; body()
                     }
                 }
                 else {
-                    body()
+                    out &lt;&lt; body()
                 }
             }
         }
@@ -84,9 +88,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def errorList = []
         if(model) {
-            errorList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors)) 
-            }
+            errorList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             errorList &lt;&lt; attrs['bean']
@@ -95,9 +97,9 @@ class ValidationTagLib {
             request.attributeNames.each {
                 def ra = request[it]
                 if(ra) {
-                    if(ra instanceof Errors)
+                    if (ra instanceof Errors)
                         errorList &lt;&lt; ra
-                    else if ((ra.errors != null) &amp;&amp; (ra.errors instanceof Errors)) {
+                    else if (ra.properties?.errors instanceof Errors) {
                         errorList &lt;&lt; ra
 					}
                 }
@@ -119,13 +121,13 @@ class ValidationTagLib {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
                         errors.getFieldErrors( attrs[&quot;field&quot;] ).each {
-                            body(it)
+                            out &lt;&lt; body(it)
                         }
                     }
                 }
                 else {
                     errors.allErrors.each {
-                        body( it )
+                        out &lt;&lt; body( it )
                     }
                 }
             }
@@ -141,9 +143,9 @@ class ValidationTagLib {
 
         if(renderAs == 'list') {
             out &lt;&lt; &quot;&lt;ul&gt;&quot;
-            eachError(attrs, {
+            out &lt;&lt; eachError(attrs, {
                 out &lt;&lt; &quot;&lt;li&gt;&quot;
-                message(error:it)
+                out &lt;&lt; message(error:it)
                 out &lt;&lt; &quot;&lt;/li&gt;&quot;
               }
             )
@@ -219,7 +221,7 @@ class ValidationTagLib {
         }
 
         def app = grailsAttributes.getGrailsApplication()
-        def dc = app.getGrailsDomainClass(againstClass)
+        def dc = app.getDomainClass(againstClass)
 
         if(!dc)
             throwTagError(&quot;Tag [validate] could not find a domain class to validate against for name [${againstClass}]&quot;)</diff>
      <filename>racetrack_ch4/plugins/core/grails-app/taglib/ValidationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ class URLCodec {
     }
 
     static decode = { obj -&gt;
-        URLEncoder.decode(obj.toString(), URLCodec.getEncoding())
+        URLDecoder.decode(obj.toString(), URLCodec.getEncoding())
     }
 
 	private static def getEncoding() {</diff>
      <filename>racetrack_ch4/plugins/core/grails-app/utils/URLCodec.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch4/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,9 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 
-&lt;beans&gt;
 	&lt;bean id=&quot;grailsApplication&quot; class=&quot;org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean&quot;&gt;
 		&lt;description&gt;Grails application factory bean&lt;/description&gt;
 		&lt;property name=&quot;groovyFiles&quot;&gt;
@@ -25,7 +27,7 @@
         &lt;property name=&quot;pluginManager&quot; ref=&quot;pluginManager&quot; /&gt;
     &lt;/bean&gt;
 	
-    &lt;bean id=&quot;grailsResourceHolder&quot; singleton=&quot;false&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
+    &lt;bean id=&quot;grailsResourceHolder&quot; scope=&quot;prototype&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
         &lt;property name=&quot;resources&quot;&gt;
               &lt;value&gt;classpath*:**/grails-app/**/*.groovy&lt;/value&gt;
         &lt;/property&gt;</diff>
      <filename>racetrack_ch4/web-app/WEB-INF/applicationContext.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch4/web-app/WEB-INF/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,254 @@
     &lt;uri&gt;http://grails.codehaus.org/tags&lt;/uri&gt;
 
     &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var}
+        &lt;/description&gt;
+        &lt;name&gt;set&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovySetTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var} into the page context
+        &lt;/description&gt;
+        &lt;name&gt;def&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyDefTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical if tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;if&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical else tag as fallback if the if condition fails
+        &lt;/description&gt;
+        &lt;name&gt;else&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical elseif tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;elseif&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;
+        	Tag to loop over a collection while the test expression returns true
+        &lt;/description&gt;
+        &lt;name&gt;while&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyWhileTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;each&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyEachTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;findAll&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyFindAllTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to filter the elements to iterate over&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and collects the elements
+        	you want to work with&lt;/description&gt;
+        &lt;name&gt;collect&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyCollectTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to use to collect the elements. The
+        	expression must retur true to add the element to the
+        	collection&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and filters the elements
+        with a regular expression&lt;/description&gt;
+        &lt;name&gt;grep&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyGrepTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The regular expression to filter the element with. The
+        	filter is a simple Groovy Regex&lt;/description&gt;
+            &lt;name&gt;filter&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;A tag that attempts to render an input for a bean property
+        into an appropriate component based on the type. It uses the templates
+        defined in &quot;grails-app/views/scaffolding&quot; to achieve this by looking up
+		the template by type.&lt;/description&gt;
+        &lt;name&gt;renderInput&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyRenderInputTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The Bean to render the input for&lt;/description&gt;
+            &lt;name&gt;bean&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The property of the bean to render input for&lt;/description&gt;
+            &lt;name&gt;property&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
         &lt;name&gt;link&lt;/name&gt;
         &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag&lt;/tag-class&gt;
         &lt;body-content&gt;JSP&lt;/body-content&gt;</diff>
      <filename>racetrack_ch4/web-app/WEB-INF/tld/grails.tld</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
 &lt;web-app version=&quot;2.4&quot;
          xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
          xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</diff>
      <filename>racetrack_ch4/web-app/WEB-INF/web.template.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
+&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;log4jRefreshInterval&lt;/param-name&gt;&lt;param-value&gt;1000&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
 		              Allows developers to view the intermediade source code, when they pass
-		                a spillGroovy argument in the URL.					
-							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file
+		                a spillGroovy argument in the URL.
+							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;*.dispatch&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch4/web-app/WEB-INF/web.xml</filename>
    </modified>
    <modified>
      <diff>@@ -124,4 +124,15 @@ td .errors {
 .prop .value {
 	text-align:left;
 	width:80%;
+}
+
+.prevLink, .step, .currentStep, .nextLink {
+	padding-right: 5px;
+}
+.currentStep {
+	font-weight:bold;
+}
+
+th.sorted a, th.sorted a:link, th.sorted a:visited, th.sorted a:hover, th.sortable a, th.sortable a:link, th.sortable a:visited, th.sortable a:hover {
+	color: white;
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch4/web-app/css/main.css</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 function warnBeforeRaceDelete() { 
      return confirm('Are you sure you want to delete this race?') 
-}
+} 
 
 function warnBeforeRegistrationDelete() { 
      return confirm('Are you sure you want to delete this registration?') 
-}
\ No newline at end of file
+} </diff>
      <filename>racetrack_ch4/web-app/js/racetrack.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,9 @@
 	&lt;classpathentry kind=&quot;src&quot; path=&quot;grails-tests&quot;/&gt;
 	&lt;classpathentry kind=&quot;con&quot; path=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot;/&gt;
 	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/ant/lib/ant.jar&quot;/&gt;
-    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
+    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-junit.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant.jar&quot; /&gt;
 
@@ -48,9 +50,9 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ejb3-persistence.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.2-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.5-SNAPSHOT.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.0.1-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.1-BETA-1.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-starter.jar&quot; /&gt;
 
@@ -80,13 +82,13 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/log4j-1.2.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ognl-2.7.jar&quot; /&gt;
-
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/org.mortbay.jetty.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/oro-2.0.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.5.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.6.0.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/serializer.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/servletapi-2.4.jar&quot; /&gt;
 
@@ -106,18 +108,20 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/standard-2.4.jar&quot; /&gt;
 
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xalan.jar&quot; /&gt;
+
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xerces-2.6.2.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xml-apis.jar&quot; /&gt;
 
 
-	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.4.2.jar&quot; /&gt;
+	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.5.jar&quot; /&gt;
 
 
 	&lt;classpathentry kind=&quot;output&quot; path=&quot;web-app/WEB-INF/classes&quot;/&gt;</diff>
      <filename>racetrack_ch5/.classpath</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-#Do not edit app.grails.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place!
-#Sun Mar 11 15:49:46 EDT 2007
-app.grails.version=0.4.2
+#Wed May 02 20:22:50 EDT 2007
+app.version=0.1
+app.grails.version=0.5
 app.name=racetrack</diff>
      <filename>racetrack_ch5/application.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class DevelopmentDataSource { 
+class DevelopmentDataSource {
    boolean pooling = true 
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_dev&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
    String password = &quot;&quot; 
-} 
+}</diff>
      <filename>racetrack_ch5/grails-app/conf/DevelopmentDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch5/grails-app/conf/log4j.development.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch5/grails-app/conf/log4j.production.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch5/grails-app/conf/log4j.test.properties</filename>
    </modified>
    <modified>
      <diff>@@ -46,8 +46,8 @@ class RaceController {
         def race = Race.get( params.id )
         if(race) {
              race.properties = params
-            if(race.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+            if(race.save()) {       
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:race.id)
             }
             else {
@@ -70,7 +70,7 @@ class RaceController {
         def race = new Race()
         race.properties = params
         if(race.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot; 
             redirect(action:show,id:race.id)
         }
         else {
@@ -78,42 +78,41 @@ class RaceController {
         }
     }
 
-    def search = { 
-        if (request.method == 'POST') { 
-            RaceQuery query = new RaceQuery() 
-            bindData(query, params) 
-
-            def criteria = Race.createCriteria() 
-
-            def results = criteria { 
-                and { 
-                    like('city', '%' + query.city + '%') 
-                    like('state', '%' + query.state + '%') 
-                    if (query.distance) { 
-                        switch (query.distanceOperator) { 
-                            case RaceQuery.DistanceOperator.AT_LEAST: 
-                                ge('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.EXACTLY: 
-                                eq('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.AT_MOST: 
-                                le('distance', query.distance) 
-                                break 
-                            default: 
-                                log.error &quot;Found unexpected value for distance&quot; 
-                                   + &quot; operator - ${query.distanceOperator}&quot; 
-                        } 
-                    } 
-                    // Add 1 day (24 hours) to the max date.  (If user selects a max 
-                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but 
-                    // the user will want any events occurring thru Jan 1st 23:59.) 
-                    between('startDateTime', query.minDate, query.maxDate + 1) 
-                } 
-            } 
-
-            render(view:'list', model:[ raceList: results ]) 
-        } 
-    } 
-
+    def search = {
+        if (request.method == 'POST') {
+            RaceQuery query = new RaceQuery()
+            bindData(query, params)
+    
+            def criteria = Race.createCriteria()
+    
+            def results = criteria {
+                and {
+                    like('city', '%' + query.city + '%')
+                    like('state', '%' + query.state + '%')
+                    if (query.distance) {
+                        switch (query.distanceOperator) {
+                            case RaceQuery.DistanceOperator.AT_LEAST:
+                                ge('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.EXACTLY:
+                                eq('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.AT_MOST:
+                                le('distance', query.distance)
+                                break
+                            default:
+                                log.error &quot;Found unexpected value for distance&quot;
+                                    + &quot; operator - ${query.distanceOperator}&quot;
+                        }
+                    }
+                    // Add 1 day (24 hours) to the max date.  If user selects a max
+                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but
+                    // the user will want any events occurring thru Jan 1st 23:59.
+                    between('startDateTime', query.minDate, query.maxDate + 1)
+                }
+            }
+    
+            render(view:'list', model:[ raceList: results.adaptee ])
+        }
+    }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch5/grails-app/controllers/RaceController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -47,7 +47,7 @@ class RegistrationController {
         if(registration) {
              registration.properties = params
             if(registration.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:registration.id)
             }
             else {
@@ -70,7 +70,7 @@ class RegistrationController {
         def registration = new Registration()
         registration.properties = params
         if(registration.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot;                 
             redirect(action:show,id:registration.id)
         }
         else {</diff>
      <filename>racetrack_ch5/grails-app/controllers/RegistrationController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Race {  
+class Race { 
     String name 
     Date startDateTime 
     String city 
@@ -7,16 +7,16 @@ class Race {
     Float cost 
     Integer maxRunners = 100000 
      
-    static hasMany = [registrations:Registration]  
+    static hasMany = [registrations:Registration]
     
     static constraints = { 
-        name(maxLength:50,blank:false) 
-        startDateTime(validator: {return (it &gt; new Date())})  
-        city(maxLength:30,blank:false) 
+        name(maxSize:50,blank:false) 
+        startDateTime(validator: {return (it &gt; new Date())}) 
+        city(maxSize:30,blank:false) 
         state(inList:['GA', 'NC', 'SC', 'VA'],blank:false) 
         distance(min:3.1f,max:100f) 
         cost(min:0f,max:999.99f) 
-    }
+    } 
     
-    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot;}     
-}
\ No newline at end of file
+    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot; }
+}	</diff>
      <filename>racetrack_ch5/grails-app/domain/Race.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Registration  {  
+class Registration { 
     Race race 
     String name 
     Date dateOfBirth 
@@ -6,19 +6,17 @@ class Registration  {
     String postalAddress 
     String emailAddress 
     Date createdAt = new Date() 
-    
+
     static belongsTo = Race 
-    
-    static optionals = [&quot;postalAddress&quot; ]  
-    
+
     static constraints = { 
-        name(maxLength:50,blank:false) 
+        name(maxSize:50,blank:false) 
         dateOfBirth(nullable:false) 
         gender(inList:[&quot;M&quot;, &quot;F&quot;]) 
-        postalAddress(maxLength:255) 
-        emailAddress(maxLength:50,email:true) 
+        postalAddress(nullable:true,maxSize:255) 
+        emailAddress(maxSize:50,email:true) 
         race(nullable:false) 
     } 
-
-  String toString() {&quot;${this.name} : ${this.emailAddress}&quot;}         
-}
\ No newline at end of file
+    
+    String toString(){&quot;${this.name}:${this.emailAddress}&quot;}         
+}	</diff>
      <filename>racetrack_ch5/grails-app/domain/Registration.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,29 +1,28 @@
 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.message=Property [{0}] of class [{1}] is not a valid [{2}].
+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.length.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
-default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
 default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
-default.invalid.max.length.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
-default.invalid.min.length.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{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.not.editable.message=Property [{0}] of class [{1}] with value [{2}] cannot be changed from [{3}] 
 
-race.name.blank=Please enter a name for this race 
+default.paginate.prev=Previous
+default.paginate.next=Next
+
+race.name.blank=Please enter a name for this race
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles 
 race.startDateTime.validator.invalid=Please enter a future date and time
 race.city.blank=Please enter a city for this race
-race.city.maxLength.exceeded=Please limit the city name to a maximum length of {3} characters
+race.city.maxSize.exceeded=Please limit the city name to a maximum length of {3} characters
 race.distance.nullable=Please enter a valid distance
 race.distance.min.notmet=Please enter a valid distance no fewer than {3} miles
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles
@@ -32,8 +31,8 @@ race.cost.min.notmet=Please enter a valid cost of at least ${3}
 race.cost.max.exceeded=Please enter a valid cost no more than ${3}
 
 registration.name.blank=Please enter a name
-registration.name.maxLength.exceeded=Please limit the name to a maximum length of {3} characters
-registration.postalAddress.maxLength.exceeded=Please limit the postal address to a maximum length of {3} characters
+registration.name.maxSize.exceeded=Please limit the name to a maximum length of {3} characters
+registration.postalAddress.maxSize.exceeded=Please limit the postal address to a maximum length of {3} characters
 registration.emailAddress.blank=Please enter an e-mail address
-registration.emailAddress.maxLength.exceeded=Please limit the e-mail address to a maximum length of {3} characters
+registration.emailAddress.maxSize.exceeded=Please limit the e-mail address to a maximum length of {3} characters
 registration.emailAddress.email.invalid=Please enter a valid e-mail address
\ No newline at end of file</diff>
      <filename>racetrack_ch5/grails-app/i18n/messages.properties</filename>
    </modified>
    <modified>
      <diff>@@ -27,19 +27,19 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/race/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -30,19 +30,19 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='registrations'&gt;Registrations:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'registrations','errors')}'&gt;&lt;ul&gt;
     &lt;g:each var='r' in='${race?.registrations?}'&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/race/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New Race&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt; 
-                &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
+                    &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
             &lt;/span&gt; 
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
@@ -23,17 +23,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Start Date Time&lt;/th&gt;
-                                      
-                        &lt;th&gt;City&lt;/th&gt;
-                                      
-                        &lt;th&gt;State&lt;/th&gt;
-                                      
-                        &lt;th&gt;Distance&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;startDateTime&quot; title=&quot;Start Date Time&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;city&quot; title=&quot;City&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;state&quot; title=&quot;State&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;distance&quot; title=&quot;Distance&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/race/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -28,34 +28,37 @@
                        &lt;label for='state'&gt;State:&lt;/label&gt; 
                    &lt;/td&gt; 
                    &lt;td valign='top' class='value'&gt; 
-                       &lt;g:select name='state' from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
+                       &lt;g:select name='state'  
+                   from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
                       &lt;/g:select&gt; 
                    &lt;/td&gt; 
                &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='date'&gt;Date:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         between 
-                         &lt;g:datePicker name='minDate' precision='day' /&gt; 
-                         and 
-                         &lt;g:datePicker name='maxDate' precision='day' value='${new Date().plus(365*2)}'/&gt; 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         &lt;select name='distanceOperator' &gt; 
-                             &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
-                             &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
-                             &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
-                         &lt;/select&gt; 
-                         &lt;input type='text' name='distance' size='5'&gt;&lt;/input&gt; mi 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt;               
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='date'&gt;Date:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     between 
+                     &lt;g:datePicker name='minDate' precision='day' /&gt; 
+                     and 
+                     &lt;g:datePicker name='maxDate' precision='day'  
+                  value='${new Date().plus(365*2)}'/&gt; 
+                 &lt;/td&gt; 
+             &lt;/tr&gt; 
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     &lt;select name='distanceOperator' &gt; 
+                         &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
+                         &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
+                         &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
+                     &lt;/select&gt; 
+                     &lt;input type='text' name='distance' size='5'&gt; 
+             &lt;/input&gt; mi 
+                 &lt;/td&gt; 
+             &lt;/tr&gt;
             &lt;/table&gt; 
             &lt;/div&gt; 
             &lt;div class=&quot;buttons&quot;&gt; </diff>
      <filename>racetrack_ch5/grails-app/views/race/search.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
   
 &lt;html&gt;
     &lt;head&gt;
-         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
+         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;  
          &lt;g:javascript library=&quot;racetrack&quot; /&gt;          
           &lt;meta name=&quot;layout&quot; content=&quot;main&quot; /&gt;
          &lt;title&gt;Show Race&lt;/title&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/race/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -27,7 +27,7 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -35,12 +35,10 @@
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='createdAt'&gt;Created At:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'createdAt','errors')}'&gt;&lt;g:datePicker name='createdAt' value=&quot;${registration?.createdAt}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
-                       
                     &lt;/tbody&gt;
                &lt;/table&gt;
                &lt;/div&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/registration/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -30,7 +30,7 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -38,7 +38,7 @@
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -50,7 +50,7 @@
 
                &lt;div class=&quot;buttons&quot;&gt;
                      &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Update&quot; /&gt;&lt;/span&gt;
-                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/div&gt;
             &lt;/g:form&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/registration/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -20,17 +20,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Date Of Birth&lt;/th&gt;
-                                      
-                        &lt;th&gt;Gender&lt;/th&gt;
-                                      
-                        &lt;th&gt;Postal Address&lt;/th&gt;
-                                      
-                        &lt;th&gt;Email Address&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;dateOfBirth&quot; title=&quot;Date Of Birth&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;gender&quot; title=&quot;Gender&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;postalAddress&quot; title=&quot;Postal Address&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;emailAddress&quot; title=&quot;Email Address&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/registration/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -77,7 +77,7 @@
                &lt;g:form controller=&quot;registration&quot;&gt;
                  &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;${registration?.id}&quot; /&gt;
                  &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Edit&quot; /&gt;&lt;/span&gt;
-                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/g:form&gt;
            &lt;/div&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch5/grails-app/views/registration/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,10 @@ import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
-class ApplicationTagLib {
+class ApplicationTagLib { 
+	
+	def grailsUrlMappingsHolder
+	
     /**
      * Creates a link to a resource, generally used as a method rather than a tag.
      *
@@ -33,7 +36,7 @@ class ApplicationTagLib {
      */
     def createLinkTo = { attrs -&gt;
          out &lt;&lt; grailsAttributes.getApplicationUri(request)
-         if(attrs['dir']) {
+         if(attrs['dir'] || attrs['dir'] == '') {
             out &lt;&lt; &quot;/${attrs['dir']}&quot;
          }
          if(attrs['file']) {
@@ -50,7 +53,7 @@ class ApplicationTagLib {
     def link = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;a href=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // process remaining attributes
@@ -59,7 +62,7 @@ class ApplicationTagLib {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -79,29 +82,47 @@ class ApplicationTagLib {
         if(attrs['url']) {
              attrs = attrs.remove('url')
         }
-        // if the current attribute null set the controller uri to the current controller
-        if(attrs[&quot;controller&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;controller&quot;)
-        }
-        else {
-           out &lt;&lt; grailsAttributes.getControllerUri(request)
-        }
-        if(attrs[&quot;action&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;action&quot;)
-        }
-        if(attrs[&quot;id&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;id&quot;)
-        }
-        if(attrs['params']) {
-            def pms = attrs.remove('params')
-            out &lt;&lt; '?'
-            def i = 0
-            pms.each { k,v -&gt;
-                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
-                if(++i &lt; pms.size())
-                   out &lt;&lt; '&amp;'
-            }
-        }
+                                                     
+		def controller = attrs.containsKey(&quot;controller&quot;) ? attrs.remove(&quot;controller&quot;) : grailsAttributes.getController(request).controllerName
+		def action = attrs.remove(&quot;action&quot;)
+        def id = attrs.remove(&quot;id&quot;)
+        def params = attrs.params ? attrs.remove('params') : [:]
+
+        def url
+		try {
+            if(id) params.id = id
+            def mapping = grailsUrlMappingsHolder?.getReverseMapping(controller,action,params)
+			params.controller = controller
+			if(action) params.action = action  
+            url = mapping?.createURL(params)
+		}        
+		finally {
+			params.remove('controller')
+			params.remove('action')          
+			params.remove('id')
+		}
+		if(url) {
+			out &lt;&lt; url
+		}             
+		else {
+            out &lt;&lt; '/' &lt;&lt; controller
+	        if(action) {
+	            out &lt;&lt; '/' &lt;&lt; action
+	        }
+	        if(id) {
+	            out &lt;&lt; '/' &lt;&lt; id
+	        }
+	        if(params) {
+	            out &lt;&lt; '?'
+	            def i = 0
+	            params.each { k,v -&gt;
+	                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
+	                if(++i &lt; params.size())
+	                   out &lt;&lt; '&amp;'
+	            }
+	        }			
+		}
+															
     }
 
 	/**
@@ -127,8 +148,8 @@ class ApplicationTagLib {
 				} 				
 			}
 		}
-		out &lt;&lt; '&gt;'
-		body()
+		out &lt;&lt; '&gt;'  
+		out &lt;&lt; body()
 		out &lt;&lt; &quot;&lt;/${attrs.name}&gt;&quot;			
 	}	
 }</diff>
      <filename>racetrack_ch5/plugins/core/grails-app/taglib/ApplicationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -16,6 +16,7 @@ import org.springframework.validation.Errors;
 import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
+import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
 
  /**
  *  A  tag lib that provides tags for working with form controls
@@ -33,7 +34,10 @@ class FormTagLib {
 	def textField = { attrs -&gt;
 		attrs.type = &quot;text&quot;  
 		attrs.tagName = &quot;textField&quot; 
-		field(attrs)
+		def result = field(attrs)
+		if(result) {     
+			out &lt;&lt; result
+		}
 	}
 	/**
 	 * Creates a hidden field
@@ -41,7 +45,7 @@ class FormTagLib {
 	def hiddenField = { attrs -&gt;
 		attrs.type = &quot;hidden&quot;
 		attrs.tagName = &quot;hiddenField&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * Creates a submit button
@@ -49,7 +53,7 @@ class FormTagLib {
 	def submitButton = { attrs -&gt;
 		attrs.type = &quot;submit&quot;
 		attrs.tagName = &quot;submitButton&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * A general tag for creating fields
@@ -84,7 +88,7 @@ class FormTagLib {
     void resolveAttributes(attrs)
     {
         if(!attrs.name &amp;&amp; !attrs.field) {
-            throwTagError(&quot;Tag [$tagName] is missing required attribute [name] or [field]&quot;)
+            throwTagError(&quot;Tag [${attrs.tagName}] is missing required attribute [name] or [field]&quot;)
         }
         attrs.remove('tagName')
 
@@ -121,7 +125,7 @@ class FormTagLib {
     def form = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;form action=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // default to post
@@ -133,26 +137,34 @@ class FormTagLib {
 
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        def bodyContent = body()
+		out &lt;&lt; bodyContent
 
         // close tag
         out &lt;&lt; &quot;&lt;/form&gt;&quot;
     }
     /**
      * Creates a submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmit value=&quot;Edit&quot; /&gt;
+     *  &lt;g:actionSubmit action=&quot;Edit&quot; value=&quot;Some label for editing&quot; /&gt;
      *
      */
     def actionSubmit = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;submit&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+    	if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
-        // process remaining attributes
+
+		// add action and value
+		def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    	
+    	out &lt;&lt; &quot;&lt;input type=\&quot;submit\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+    	
+    	// process remaining attributes
         outputAttributes(attrs)
 
         // close tag
@@ -161,22 +173,30 @@ class FormTagLib {
     }
     /**
      * Creates a an image submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmitImage src=&quot;/images/submitButton.gif&quot; action=&quot;Edit&quot; /&gt;
      *
      */
     def actionSubmitImage = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;image&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+        if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
+        
+        // add action and value
+        def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    
+        out &lt;&lt; &quot;&lt;input type=\&quot;image\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+
+		// add image src        
         def src = attrs.remove('src')
         if(src) {
              out &lt;&lt; &quot;src=\&quot;${src}\&quot; &quot;
         }
+
         // process remaining attributes
         outputAttributes(attrs)
 
@@ -201,6 +221,8 @@ class FormTagLib {
 
         def value = (attrs['value'] ? attrs['value'] : xdefault)
         def name = attrs['name']
+        def id = attrs['id'] ? attrs['id'] : name
+
 		def noSelection = attrs['noSelection']
 		if (noSelection != null)
 		{
@@ -253,7 +275,7 @@ class FormTagLib {
 
         // create day select
         if (precision &gt;= PRECISION_RANKINGS[&quot;day&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_day\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_day\&quot; id=\&quot;${id}_day\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -272,7 +294,7 @@ class FormTagLib {
 
         // create month select
         if (precision &gt;= PRECISION_RANKINGS[&quot;month&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_month\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_month\&quot; id=\&quot;${id}_month\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -294,7 +316,7 @@ class FormTagLib {
 
         // create year select
         if (precision &gt;= PRECISION_RANKINGS[&quot;year&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_year\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_year\&quot; id=\&quot;${id}_year\&quot;&gt;&quot;
 
             if (noSelection) {
     			renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -313,7 +335,7 @@ class FormTagLib {
 
         // do hour select
         if (precision &gt;= PRECISION_RANKINGS[&quot;hour&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot; id=\&quot;${id}_hour\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -338,7 +360,7 @@ class FormTagLib {
 
         // do minute select
         if (precision &gt;= PRECISION_RANKINGS[&quot;minute&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot; id=\&quot;${id}_minute\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -360,7 +382,7 @@ class FormTagLib {
 	def renderNoSelectionOption = { noSelectionKey, noSelectionValue, value -&gt;
 		// If a label for the '--Please choose--' first item is supplied, write it out
         out &lt;&lt; '&lt;option value=&quot;' &lt;&lt; (noSelectionKey == null ? &quot;&quot; : noSelectionKey) &lt;&lt; '&quot;'
-        if(noSelectionKey == value) {
+        if(noSelectionKey.equals(value)) {
             out &lt;&lt; ' selected=&quot;selected&quot; '
         }
         out &lt;&lt; '&gt;' &lt;&lt; noSelectionValue.encodeAsHTML() &lt;&lt; '&lt;/option&gt;'
@@ -388,7 +410,7 @@ class FormTagLib {
         }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -405,7 +427,7 @@ class FormTagLib {
         attrs['optionValue'] = { &quot;${it.language}, ${it.country},  ${it.displayName}&quot; }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -425,7 +447,7 @@ class FormTagLib {
 		   	attrs.value = null
 		}
         // invoke generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -436,11 +458,15 @@ class FormTagLib {
      * &lt;g:select name=&quot;user.company.id&quot; from=&quot;${Company.list()}&quot; value=&quot;${user?.company.id}&quot; optionKey=&quot;id&quot; /&gt;
      */
     def select = { attrs -&gt;
+	    def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request)
+
         def from = attrs.remove('from')
         def keys = attrs.remove('keys')
         def optionKey = attrs.remove('optionKey')
         def optionValue = attrs.remove('optionValue')
         def value = attrs.remove('value')
+        def valueMessagePrefix = attrs.remove('valueMessagePrefix')
 		def noSelection = attrs.remove('noSelection')
         if (noSelection != null) {
             noSelection = noSelection.entrySet().iterator().next()
@@ -461,20 +487,21 @@ class FormTagLib {
         // create options from list
         if(from) {
             from.eachWithIndex { el,i -&gt;
+            	def keyValue = null
                 out &lt;&lt; '&lt;option '
                 if(keys) {
-                    out &lt;&lt; 'value=&quot;' &lt;&lt; keys[i] &lt;&lt; '&quot; '
-                    if(keys[i] == value) {
+                    keyValue = keys[i]
+                    out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
-               else if(optionKey) {
-                    def keyValue = null
+                else if(optionKey) {
                     if(optionKey instanceof Closure) {
                         keyValue = optionKey(el)
-                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                        out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
-                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getGrailsDomainClass(el.getClass().name)) {
+                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, el.getClass().name)) {
                         keyValue = el.ident()
                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
@@ -488,8 +515,9 @@ class FormTagLib {
                     }
                 }
                 else {
-                    out &lt;&lt; &quot;value=\&quot;${el}\&quot; &quot;
-                    if(el == value) {
+                	keyValue = el
+                    out &lt;&lt; &quot;value=\&quot;${keyValue}\&quot; &quot;
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
@@ -502,6 +530,19 @@ class FormTagLib {
                         out &lt;&lt; el.properties[optionValue].toString().encodeAsHTML()
                     }
                 }
+                else if(valueMessagePrefix) {
+                	def message = messageSource.getMessage(&quot;${valueMessagePrefix}.${keyValue}&quot;, null, null, locale)
+                	if(message) {
+                		out &lt;&lt; message.encodeAsHTML()
+                	}
+                	else if (keyValue) {
+                		out &lt;&lt; keyValue.encodeAsHTML()
+                	}
+					else {
+        	            def s = el.toString()
+    	                if(s) out &lt;&lt; s.encodeAsHTML()
+	                }
+                }
                 else {
                     def s = el.toString()
                     if(s) out &lt;&lt; s.encodeAsHTML()
@@ -554,6 +595,6 @@ class FormTagLib {
         outputAttributes(attrs)
 
         // close the tag, with no body
-        out &lt;&lt; ' &gt;&lt;/input&gt;'
+        out &lt;&lt; ' /&gt;'
      }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch5/plugins/core/grails-app/taglib/FormTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ class JavascriptTagLib  {
 		}
 		else {
 			out.println '&lt;script type=&quot;text/javascript&quot;&gt;'
-				body()
+				out &lt;&lt; body()
 			out.println '&lt;/script&gt;'
 		}
 	}
@@ -137,15 +137,15 @@ class JavascriptTagLib  {
     /**
      * A link to a remote uri that used the prototype library to invoke the link via ajax
      */
-    def remoteLink = { attrs, body -&gt;
+    def remoteLink = { attrs, body -&gt;  
        out &lt;&lt; &quot;&lt;a href=\&quot;&quot;    
 
        def cloned = deepClone(attrs)
-	   createLink(cloned)               
+	   out &lt;&lt; createLink(cloned)               
 
 	   out &lt;&lt; &quot;\&quot; onclick=\&quot;&quot;
         // create remote function
-        remoteFunction(attrs)   
+        out &lt;&lt; remoteFunction(attrs)   
 		attrs.remove('url')
         out &lt;&lt; &quot;return false;\&quot; &quot;
         // process remaining attributes
@@ -154,7 +154,7 @@ class JavascriptTagLib  {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -180,7 +180,7 @@ class JavascriptTagLib  {
 		else {
     		attrs.params = &quot;'${paramName}='+this.value&quot;			
 		}
-		remoteFunction(attrs)
+		out &lt;&lt; remoteFunction(attrs)
 		attrs.remove('params')
 		out &lt;&lt; &quot;\&quot;&quot;   
 		attrs.remove('url')
@@ -208,16 +208,16 @@ class JavascriptTagLib  {
 		// prepare form settings
 		prepareAjaxForm(p,attrs)
         
-        def params = [  onsubmit:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onsubmit:remoteFunction(attrs) + 'return false',
 					    method: (attrs.method? attrs.method : 'POST' ),
-					    action: (attrs.action? attrs.action : TagLibUtil.outToString(createLink,url))		                 
+					    action: (attrs.action? attrs.action : createLink(url))		                 
 		             ]
 		attrs.remove('url')		             
 	    params.putAll(attrs)
 		if(params.name &amp;&amp; !params.id)
 			params.id = params.name
-	    withTag(name:'form',attrs:params) {
-			body()   
+	    out &lt;&lt; withTag(name:'form',attrs:params) {
+			out &lt;&lt; body()   
 	    }		
     }
 
@@ -230,7 +230,7 @@ class JavascriptTagLib  {
 		// prepare form settings 
 		attrs.forSubmitTag = &quot;.form&quot;
 		prepareAjaxForm(p,attrs)    
-        def params = [  onclick:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onclick:remoteFunction(attrs) + 'return false',
 					    type: 'button',
 					    name: attrs.remove('name'),
 					    value: attrs.remove('value'), 
@@ -238,8 +238,8 @@ class JavascriptTagLib  {
 					    'class':attrs.remove('class')
 		             ]
 		             
-		withTag(name:'input', attrs:params) {
-			body()	
+		out &lt;&lt; withTag(name:'input', attrs:params) {
+			out &lt;&lt; body()	
 		}
     }
 	
@@ -275,7 +275,7 @@ class JavascriptTagLib  {
 			def sw = new StringWriter()
 			out = new PrintWriter(out)
 			// invoke body
-			body()
+			out &lt;&lt; body()
 			// restore out
 			out = tmp
 			js = sw.toString()
@@ -357,10 +357,10 @@ class PrototypeProvider implements JavascriptProvider {
 		
 		def pms = attrs.remove('params')   
 		if(attrs.url) {
-			taglib.createLink(attrs.url)			
+			out &lt;&lt; taglib.createLink(attrs.url)			
 		}                              
 		else {
-			taglib.createLink(attrs)			
+			out &lt;&lt; taglib.createLink(attrs)			
 		}
 
 		
@@ -415,6 +415,7 @@ class PrototypeProvider implements JavascriptProvider {
 	                    case 'true': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case 'false': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case ~/\s*function(\w*)\s*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
+	                    case ~/Insertion\..*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    default:ajaxOptions &lt;&lt; &quot;${k}:'${v}'&quot;; break;
 	                 }            	
             	}
@@ -441,10 +442,10 @@ class YahooProvider implements JavascriptProvider {
 		out &lt;&lt; &quot;YAHOO.util.Connect.asyncRequest('${method}','&quot;
 				
 		if(attrs.url) {
-			taglib.createLink(attrs.url)
+			out &lt;&lt; taglib.createLink(attrs.url)
 		}
 		else {
-			taglib.createLink(attrs)
+			out &lt;&lt; taglib.createLink(attrs)
 		}		
 		attrs.remove('url')
 		out &lt;&lt; &quot;',&quot;
@@ -504,7 +505,7 @@ class DojoProvider implements JavascriptProvider {
 		}		
 		 out &lt;&lt; 'dojo.io.bind({url:\''
 
-		 taglib.createLink(attrs) 
+		 out &lt;&lt; taglib.createLink(attrs) 
 		attrs.remove('params')
 		 out &lt;&lt; '\',load:function(type,data,evt) {'
 	    if(attrs.onLoaded) {</diff>
      <filename>racetrack_ch5/plugins/core/grails-app/taglib/JavascriptTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,6 +25,7 @@ import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
 class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants {
+	def out // to facilitate testing
 
     protected getPage() {
     	return request[PAGE]
@@ -91,7 +92,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 				}
 			}
 			if(invokeBody) {
-				body();	
+				out &lt;&lt; body()
 			}
 		}
 	}
@@ -134,54 +135,183 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         if(attrs.total == null)
             throwTagError(&quot;Tag [paginate] is missing required attribute [total]&quot;)
 		
-		def mkp = new groovy.xml.MarkupBuilder(out)
+		def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request) 
+		
 		def total = attrs.total.toInteger()
-		def max = params.max?.toInteger()
-		def offset = params.offset?.toInteger() 
 		def action = (attrs.action? attrs.action : 'list')
-		def breadcrumb = true
-		if(attrs.breadcrumb) breadcrumb = Boolean.valueOf(attrs.breadcrumb)
-			
+		def offset = params.offset?.toInteger()
+		def max = params.max?.toInteger()
+		def maxsteps = (attrs.maxsteps ? attrs.maxsteps.toInteger() : 10)
+
+        if(attrs.breadcrumb) {
+			log.warn(&quot;Tag [paginate] includes the [breadcrumb] attribute. This attribute is deprecated and will be removed in the future. Please update your code to use the [maxsteps] attribute instead.&quot;)
+		}
+
+		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)			
 		if(!max) max = (attrs.max ? attrs.max.toInteger() : 10)
-		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)
 		
-		def linkParams = [offset:offset-max,max:max]
-		def linkTagAttrs = ['class':'prevLink',action:action]
+		def linkParams = [offset:offset - max, max:max]
+		if(params.sort) linkParams.sort = params.sort
+		if(params.order) linkParams.order = params.order
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		def linkTagAttrs = [action:action]
 		if(attrs.controller) {
 			linkTagAttrs.controller = attrs.controller	
 		}
 		if(attrs.id) {
 			linkTagAttrs.id = attrs.id	
 		}
-		if(attrs.params)linkParams.putAll(attrs.params)
 		linkTagAttrs.params = linkParams
-	
-		def combined = max + offset
-		if(offset &gt; 0) {			
-			link(linkTagAttrs.clone(),{out&lt;&lt; (attrs.prev? attrs.prev : 'Previous' ) })
+		
+		// determine paging variables
+		def steps = maxsteps &gt; 0
+		int currentstep = (offset / max) + 1
+		int firststep = 1
+		int laststep = Math.round(Math.ceil(total / max))
+			
+		// display previous link when not on firststep
+		if(currentstep &gt; firststep) {
+			linkTagAttrs.class = 'prevLink'
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.prev ? attrs.prev : messageSource.getMessage('default.paginate.prev', null, 'Previous', locale))
+			 }
 		}
 		
-		if(total &gt; max) {
-			linkTagAttrs.'class' = 'step'
-			if(breadcrumb) {
-				def j = 0
-				0.step(total,max) { i -&gt;
-					if(offset == i) {
-						mkp.a('class':'step',&quot;${++j}&quot;)	
-					}
-					else {
-						linkParams.offset=i
-						link(linkTagAttrs.clone(),{out&lt;&lt;++j})	
-					}
-				}			
+		// display steps when steps are enabled and laststep is not firststep
+		if(steps &amp;&amp; laststep &gt; firststep) {
+			linkTagAttrs.class = 'step'
+
+			// determine begin and endstep paging variables
+			int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
+			int endstep = currentstep + Math.round(maxsteps / 2) - 1
+			
+			if(beginstep &lt; firststep) {
+				beginstep = firststep
+				endstep = maxsteps
+			}
+			if(endstep &gt; laststep) {
+				beginstep = laststep - maxsteps + 1
+				if(beginstep &lt; firststep) {
+					beginstep = firststep
+				}
+				endstep = laststep
+			}
+
+			// display firststep link when beginstep is not firststep
+			if(beginstep &gt; firststep) {
+				linkParams.offset = 0
+				out &lt;&lt; link(linkTagAttrs.clone()) {firststep.toString()}
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+			}
+
+			// display paginate steps
+			(beginstep..endstep).each { i -&gt;
+				if(currentstep == i) {
+					out &lt;&lt; &quot;&lt;span class=\&quot;currentStep\&quot;&gt;${i}&lt;/span&gt;&quot;
+				}
+				else {
+					linkParams.offset = (i - 1) * max
+					out &lt;&lt; link(linkTagAttrs.clone()) {i.toString()}
+				}
+			}	
+			
+			// display laststep link when endstep is not laststep
+			if(endstep &lt; laststep) {
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+				linkParams.offset = (laststep -1) * max
+				out &lt;&lt; link(linkTagAttrs.clone()) { laststep.toString() }
+			}		
+		}
+		
+		// display next link when not on laststep
+		if(currentstep &lt; laststep) {	
+			linkTagAttrs.class = 'nextLink'			
+			linkParams.offset = offset + max
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.next ? attrs.next : messageSource.getMessage('default.paginate.next', null, 'Next', locale))
 			}			
 		}
-		linkParams.offset = offset+max
-		if(combined &lt; total) {	
-			linkTagAttrs.'class'='nextLink'			
-			link(linkTagAttrs,{out&lt;&lt; (attrs.'next'? attrs.'next' : 'Next' )})			
+
+	}
+
+	/**
+	 * Renders a sortable column to support sorting in list views
+	 *
+	 * Attributes:
+	 *
+	 * property - name of the property relating to the field
+	 * defaultOrder (optional) - default order for the property; choose between asc (default if not provided) and desc
+	 * title (optional*) - title caption for the column
+	 * titleKey (optional*) - title key to use for the column, resolved against the message source
+	 * params (optional) - a map containing request parameters
+	 *
+	 * Attribute title or titleKey is required. When both attributes are specified then titleKey takes precedence,
+	 * resulting in the title caption to be resolved against the message source. In case when the message could
+	 * not be resolved, the title will be used as title caption. 
+	 *
+	 * Examples:
+	 *
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; style=&quot;width: 200px&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; titleKey=&quot;book.title&quot; /&gt;	 
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; titleKey=&quot;book.releaseDate&quot; /&gt;
+	 */
+	def sortableColumn = { attrs -&gt;
+
+		if(!attrs.property)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [property]&quot;) 
+		
+		if(!attrs.title &amp;&amp; !attrs.titleKey)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [title] or [titleKey]&quot;)
+
+		def property = attrs.remove(&quot;property&quot;)
+		def action = attrs.action ? attrs.remove(&quot;action&quot;) : &quot;list&quot;
+		
+		def defaultOrder = attrs.remove(&quot;defaultOrder&quot;)
+		if(defaultOrder != &quot;desc&quot;) defaultOrder = &quot;asc&quot;
+
+		// current sorting property and order
+		def sort = params.sort
+		def order = params.order
+
+		// add sorting property and params to link params
+		def linkParams = [sort:property]
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		// determine and add sorting order for this column to link params
+		attrs.class = &quot;sortable&quot;
+		if(property == sort) {
+			attrs.class = attrs.class + &quot; sorted &quot; + order
+			if(order == &quot;asc&quot;) {
+				linkParams.order = &quot;desc&quot;
+			}
+			else {
+				linkParams.order = &quot;asc&quot;
+			}
+		}
+		else {
+			linkParams.order = defaultOrder
+		}
+
+		// determine column title
+		def title = attrs.remove(&quot;title&quot;)
+		def titleKey = attrs.remove(&quot;titleKey&quot;)
+		if(titleKey) {
+			if(!title) title = titleKey
+			def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+			def locale = RCU.getLocale(request)
+			title = messageSource.getMessage(titleKey, null, title, locale)
 		}
 
+		out &lt;&lt; &quot;&lt;th &quot;
+		// process remaining attributes
+		attrs.each { k, v -&gt;
+			out &lt;&lt; &quot;${k}=\&quot;${v.encodeAsHTML()}\&quot; &quot;
+		}
+		out &lt;&lt; &quot;&gt;${link(action:action, params:linkParams) { title }}&lt;/th&gt;&quot;
 	}
 
     /**
@@ -199,14 +329,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         def uri = grailsAttributes.getTemplateUri(attrs.template,request)
         def var = attrs['var']
 
-        def url = servletContext.getResource(uri)
-        if(!url)
-            throwTagError(&quot;No template found for name [${attrs.template}] in tag [render]&quot;)
-
-        def t = engine.createTemplate(  uri,
-                                        servletContext,
-                                        request,
-                                        response)
+        def t = engine.createTemplate( uri )
 
         if(attrs.model instanceof Map) {
             t.make( attrs.model ).writeTo(out)
@@ -246,14 +369,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 	        def engine = grailsAttributes.getPagesTemplateEngine()
 	        def uri = grailsAttributes.getTemplateUri(attrs.template,request)
 
-	        def url = servletContext.getResource(uri)
-	        if(!url)
-	            throwTagError(&quot;No template found for name [${attrs.template}] in tag [include]&quot;)
-
-	        def t = engine.createTemplate(  uri,
-	                                        servletContext,
-	                                        request,
-	                                        response)
+	        def t = engine.createTemplate(  uri )
 			
 			t.make().writeTo(out)
 		}</diff>
      <filename>racetrack_ch5/plugins/core/grails-app/taglib/RenderTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -152,7 +152,7 @@ class UITagLib {
 	 * &lt;g:richTextEditor name=&quot;editor&quot; height=&quot;400&quot; /&gt;
 	 */
 	def richTextEditor = { attrs -&gt;
-		withTag(name:'script',attributes:[type:'text/javascript']) {
+		out &lt;&lt; withTag(name:'script',attributes:[type:'text/javascript']) {
 			if(attrs.onComplete) {
 				out.println &quot;function FCKeditor_OnComplete( editorInstance ) {&quot;
 					out.println &quot;${attrs.onComplete}(editorInstance);&quot;					
@@ -162,24 +162,53 @@ class UITagLib {
 			var oFCKeditor = new FCKeditor( '${attrs.name}' ) ;
 			oFCKeditor.BasePath	 = \&quot;&quot;&quot;&quot;
 			if(attrs.basepath) {
-				createLinkTo(dir:attrs.basepath)
+				out &lt;&lt; createLinkTo(dir:attrs.basepath)
 			}
 			else {
-				createLinkTo(dir:&quot;fckeditor/&quot;)
+			    out &lt;&lt; createLinkTo(dir:&quot;fckeditor/&quot;)
 			}
 			out.println '&quot;;'
 			if(attrs.toolbar) {
 				out &lt;&lt; &quot;oFCKeditor.ToolbarSet	 = '${attrs.toolbar}';&quot; 	
-			}			
+			}
+			// add width support
+			if(attrs.width)			
+				out.println &quot;oFCKeditor.Width	= '${attrs.width}';&quot;
+			
 			if(attrs.height)			
-				out.println &quot;oFCKeditor.Height	= ${attrs.height};&quot;
+				out.println &quot;oFCKeditor.Height	= '${attrs.height}';&quot;
+			
+			// add skin support, values to choose: &quot;default&quot;, &quot;office2003&quot;, &quot;silver&quot;
+			if(attrs.skin)
+				out.println &quot;oFCKeditor.Config['SkinPath'] = 'skins/${attrs.skin}/';&quot;
+			
+			// check the browser compatibility when rendering the editor.  default value: true, values to choose: true, false, 
+			if(attrs.checkBrowser)
+				out.println &quot;oFCKeditor.CheckBrowser = ${attrs.checkBrowser};&quot;
+
+			// show error messages on errors while rendering the editor.   default value: true, values to choose: true, false
+			if(attrs.displayErrors)
+				out.println &quot;oFCKeditor.DisplayErrors = ${attrs.displayErrors};&quot;
+
+			// oFCKeditor.Config      AutoDetectLanguage:true/false, DefaultLanguage:'pt-BR' and so on
+			if(attrs.config) {
+				if (attrs.config instanceof Map) {
+					attrs.config.each { k, v -&gt;
+						out.println &quot;oFCKeditor.Config['$k'] = '$v';&quot;
+					}
+				} else {
+					throw new Exception(&quot;&quot;&quot;The format of config is not correct, it should be like &quot;[AutoDetectLanguage:false, DefaultLanguage:'pt-BR']&quot;   &quot;&quot;&quot;)
+				}
+			}
+
 			if(attrs.value) {
 				out &lt;&lt; &quot;oFCKeditor.Value	= \&quot;&quot;
-				escapeJavascript(Collections.EMPTY_MAP,attrs.value)
+			    out &lt;&lt; escapeJavascript(Collections.EMPTY_MAP,attrs.value)
 				out.println &quot;\&quot; ;&quot;
 			}
 			
-			out.println &quot;oFCKeditor.Create();&quot;			
+			out.println &quot;oFCKeditor.Create();&quot;	
+
 		}
 	}
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch5/plugins/core/grails-app/taglib/UITagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -32,9 +32,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def checkList = []
         if(model) {
-            checkList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors))
-            }
+            checkList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             checkList &lt;&lt; attrs['bean']
@@ -45,7 +43,7 @@ class ValidationTagLib {
 					if(ra) {
                         if(ra instanceof Errors)
                             checkList &lt;&lt; ra
-	                    else if ((ra.properties.errors) &amp;&amp; (ra.errors instanceof Errors)) {
+	                    else if (ra.properties?.errors instanceof Errors) {
                             checkList &lt;&lt; ra
 						}
 					}
@@ -55,23 +53,29 @@ class ValidationTagLib {
 
         for(i in checkList) {
             def errors = null
-            if(i instanceof Errors) {
+            if (i instanceof Errors) {
                errors = i
             }
-            else {
-				if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
-	                if (i.hasErrors())
-	                    errors = i.errors
-	            }
+            else {       
+				try {
+					if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
+		                if (i.hasErrors())
+		                    errors = i.errors
+		            }
+					
+				}   
+				catch(MissingPropertyException mpe) {
+					// ignore
+				}
 			}
             if(errors) {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
-                        body()
+                        out &lt;&lt; body()
                     }
                 }
                 else {
-                    body()
+                    out &lt;&lt; body()
                 }
             }
         }
@@ -84,9 +88,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def errorList = []
         if(model) {
-            errorList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors)) 
-            }
+            errorList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             errorList &lt;&lt; attrs['bean']
@@ -95,9 +97,9 @@ class ValidationTagLib {
             request.attributeNames.each {
                 def ra = request[it]
                 if(ra) {
-                    if(ra instanceof Errors)
+                    if (ra instanceof Errors)
                         errorList &lt;&lt; ra
-                    else if ((ra.errors != null) &amp;&amp; (ra.errors instanceof Errors)) {
+                    else if (ra.properties?.errors instanceof Errors) {
                         errorList &lt;&lt; ra
 					}
                 }
@@ -119,13 +121,13 @@ class ValidationTagLib {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
                         errors.getFieldErrors( attrs[&quot;field&quot;] ).each {
-                            body(it)
+                            out &lt;&lt; body(it)
                         }
                     }
                 }
                 else {
                     errors.allErrors.each {
-                        body( it )
+                        out &lt;&lt; body( it )
                     }
                 }
             }
@@ -141,9 +143,9 @@ class ValidationTagLib {
 
         if(renderAs == 'list') {
             out &lt;&lt; &quot;&lt;ul&gt;&quot;
-            eachError(attrs, {
+            out &lt;&lt; eachError(attrs, {
                 out &lt;&lt; &quot;&lt;li&gt;&quot;
-                message(error:it)
+                out &lt;&lt; message(error:it)
                 out &lt;&lt; &quot;&lt;/li&gt;&quot;
               }
             )
@@ -219,7 +221,7 @@ class ValidationTagLib {
         }
 
         def app = grailsAttributes.getGrailsApplication()
-        def dc = app.getGrailsDomainClass(againstClass)
+        def dc = app.getDomainClass(againstClass)
 
         if(!dc)
             throwTagError(&quot;Tag [validate] could not find a domain class to validate against for name [${againstClass}]&quot;)</diff>
      <filename>racetrack_ch5/plugins/core/grails-app/taglib/ValidationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ class URLCodec {
     }
 
     static decode = { obj -&gt;
-        URLEncoder.decode(obj.toString(), URLCodec.getEncoding())
+        URLDecoder.decode(obj.toString(), URLCodec.getEncoding())
     }
 
 	private static def getEncoding() {</diff>
      <filename>racetrack_ch5/plugins/core/grails-app/utils/URLCodec.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch5/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,9 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 
-&lt;beans&gt;
 	&lt;bean id=&quot;grailsApplication&quot; class=&quot;org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean&quot;&gt;
 		&lt;description&gt;Grails application factory bean&lt;/description&gt;
 		&lt;property name=&quot;groovyFiles&quot;&gt;
@@ -25,7 +27,7 @@
         &lt;property name=&quot;pluginManager&quot; ref=&quot;pluginManager&quot; /&gt;
     &lt;/bean&gt;
 	
-    &lt;bean id=&quot;grailsResourceHolder&quot; singleton=&quot;false&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
+    &lt;bean id=&quot;grailsResourceHolder&quot; scope=&quot;prototype&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
         &lt;property name=&quot;resources&quot;&gt;
               &lt;value&gt;classpath*:**/grails-app/**/*.groovy&lt;/value&gt;
         &lt;/property&gt;</diff>
      <filename>racetrack_ch5/web-app/WEB-INF/applicationContext.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch5/web-app/WEB-INF/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,254 @@
     &lt;uri&gt;http://grails.codehaus.org/tags&lt;/uri&gt;
 
     &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var}
+        &lt;/description&gt;
+        &lt;name&gt;set&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovySetTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var} into the page context
+        &lt;/description&gt;
+        &lt;name&gt;def&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyDefTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical if tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;if&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical else tag as fallback if the if condition fails
+        &lt;/description&gt;
+        &lt;name&gt;else&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical elseif tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;elseif&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;
+        	Tag to loop over a collection while the test expression returns true
+        &lt;/description&gt;
+        &lt;name&gt;while&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyWhileTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;each&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyEachTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;findAll&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyFindAllTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to filter the elements to iterate over&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and collects the elements
+        	you want to work with&lt;/description&gt;
+        &lt;name&gt;collect&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyCollectTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to use to collect the elements. The
+        	expression must retur true to add the element to the
+        	collection&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and filters the elements
+        with a regular expression&lt;/description&gt;
+        &lt;name&gt;grep&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyGrepTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The regular expression to filter the element with. The
+        	filter is a simple Groovy Regex&lt;/description&gt;
+            &lt;name&gt;filter&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;A tag that attempts to render an input for a bean property
+        into an appropriate component based on the type. It uses the templates
+        defined in &quot;grails-app/views/scaffolding&quot; to achieve this by looking up
+		the template by type.&lt;/description&gt;
+        &lt;name&gt;renderInput&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyRenderInputTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The Bean to render the input for&lt;/description&gt;
+            &lt;name&gt;bean&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The property of the bean to render input for&lt;/description&gt;
+            &lt;name&gt;property&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
         &lt;name&gt;link&lt;/name&gt;
         &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag&lt;/tag-class&gt;
         &lt;body-content&gt;JSP&lt;/body-content&gt;</diff>
      <filename>racetrack_ch5/web-app/WEB-INF/tld/grails.tld</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
 &lt;web-app version=&quot;2.4&quot;
          xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
          xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</diff>
      <filename>racetrack_ch5/web-app/WEB-INF/web.template.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
+&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;log4jRefreshInterval&lt;/param-name&gt;&lt;param-value&gt;1000&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
 		              Allows developers to view the intermediade source code, when they pass
-		                a spillGroovy argument in the URL.					
-							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file
+		                a spillGroovy argument in the URL.
+							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;*.dispatch&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch5/web-app/WEB-INF/web.xml</filename>
    </modified>
    <modified>
      <diff>@@ -124,4 +124,15 @@ td .errors {
 .prop .value {
 	text-align:left;
 	width:80%;
+}
+
+.prevLink, .step, .currentStep, .nextLink {
+	padding-right: 5px;
+}
+.currentStep {
+	font-weight:bold;
+}
+
+th.sorted a, th.sorted a:link, th.sorted a:visited, th.sorted a:hover, th.sortable a, th.sortable a:link, th.sortable a:visited, th.sortable a:hover {
+	color: white;
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch5/web-app/css/main.css</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 function warnBeforeRaceDelete() { 
      return confirm('Are you sure you want to delete this race?') 
-}
+} 
 
 function warnBeforeRegistrationDelete() { 
      return confirm('Are you sure you want to delete this registration?') 
-}
\ No newline at end of file
+} </diff>
      <filename>racetrack_ch5/web-app/js/racetrack.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,9 @@
 	&lt;classpathentry kind=&quot;src&quot; path=&quot;grails-tests&quot;/&gt;
 	&lt;classpathentry kind=&quot;con&quot; path=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot;/&gt;
 	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/ant/lib/ant.jar&quot;/&gt;
-    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
+    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-junit.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant.jar&quot; /&gt;
 
@@ -48,9 +50,9 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ejb3-persistence.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.2-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.5-SNAPSHOT.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.0.1-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.1-BETA-1.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-starter.jar&quot; /&gt;
 
@@ -80,13 +82,13 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/log4j-1.2.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ognl-2.7.jar&quot; /&gt;
-
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/org.mortbay.jetty.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/oro-2.0.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.5.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.6.0.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/serializer.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/servletapi-2.4.jar&quot; /&gt;
 
@@ -106,18 +108,20 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/standard-2.4.jar&quot; /&gt;
 
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xalan.jar&quot; /&gt;
+
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xerces-2.6.2.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xml-apis.jar&quot; /&gt;
 
 
-	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.4.2.jar&quot; /&gt;
+	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.5.jar&quot; /&gt;
 
 
 	&lt;classpathentry kind=&quot;output&quot; path=&quot;web-app/WEB-INF/classes&quot;/&gt;</diff>
      <filename>racetrack_ch6/.classpath</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-#Do not edit app.grails.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place!
-#Sun Mar 11 15:49:46 EDT 2007
-app.grails.version=0.4.2
+#Wed May 02 20:22:50 EDT 2007
+app.version=0.1
+app.grails.version=0.5
 app.name=racetrack</diff>
      <filename>racetrack_ch6/application.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,12 @@
-class ApplicationBootStrap { 
-    def init = { servletContext -&gt; 
+class ApplicationBootStrap {
+
+     def init = { servletContext -&gt;
         final String BACKUP_ADMIN = 'adminjoe' 
         if (!User.findByUserId(BACKUP_ADMIN)) { 
             new User(userId:BACKUP_ADMIN,password:'password').save() 
         } 
-    } 
- 
-    def destroy = { 
-    } 
-} 
+     }       
+     
+     def destroy = {
+     }
+} 
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/conf/ApplicationBootStrap.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class DevelopmentDataSource { 
+class DevelopmentDataSource {
    boolean pooling = true 
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_dev&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
    String password = &quot;&quot; 
-} 
+}</diff>
      <filename>racetrack_ch6/grails-app/conf/DevelopmentDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch6/grails-app/conf/log4j.development.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch6/grails-app/conf/log4j.production.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch6/grails-app/conf/log4j.test.properties</filename>
    </modified>
    <modified>
      <diff>@@ -2,11 +2,13 @@ abstract class BaseController {
     def auth() { 
         if(!session.userId) { 
             def originalRequestParams = [controller:controllerName, action:actionName] 
+
             originalRequestParams.putAll(params) 
+
             session.originalRequestParams = originalRequestParams 
 
             redirect(controller:'user',action:'login') 
             return false 
         } 
-    } 
-}
\ No newline at end of file
+    }  
+} 
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/controllers/BaseController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
             
-class RaceController extends BaseController {
-    def beforeInterceptor = [action:this.&amp;auth, except:['search']] 
+class RaceController extends BaseController { 
+    def beforeInterceptor = [action:this.&amp;auth, except:['search']]
     
     def index = { redirect(action:list,params:params) }
 
@@ -48,8 +48,8 @@ class RaceController extends BaseController {
         def race = Race.get( params.id )
         if(race) {
              race.properties = params
-            if(race.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+            if(race.save()) {       
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:race.id)
             }
             else {
@@ -72,7 +72,7 @@ class RaceController extends BaseController {
         def race = new Race()
         race.properties = params
         if(race.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot; 
             redirect(action:show,id:race.id)
         }
         else {
@@ -80,42 +80,41 @@ class RaceController extends BaseController {
         }
     }
 
-    def search = { 
-        if (request.method == 'POST') { 
-            RaceQuery query = new RaceQuery() 
-            bindData(query, params) 
-
-            def criteria = Race.createCriteria() 
-
-            def results = criteria { 
-                and { 
-                    like('city', '%' + query.city + '%') 
-                    like('state', '%' + query.state + '%') 
-                    if (query.distance) { 
-                        switch (query.distanceOperator) { 
-                            case RaceQuery.DistanceOperator.AT_LEAST: 
-                                ge('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.EXACTLY: 
-                                eq('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.AT_MOST: 
-                                le('distance', query.distance) 
-                                break 
-                            default: 
-                                log.error &quot;Found unexpected value for distance&quot; 
-                                   + &quot; operator - ${query.distanceOperator}&quot; 
-                        } 
-                    } 
-                    // Add 1 day (24 hours) to the max date.  (If user selects a max 
-                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but 
-                    // the user will want any events occurring thru Jan 1st 23:59.) 
-                    between('startDateTime', query.minDate, query.maxDate + 1) 
-                } 
-            } 
-
-            render(view:'searchresults', model:[ raceList: results ])  
-        } 
-    } 
-
+    def search = {
+        if (request.method == 'POST') {
+            RaceQuery query = new RaceQuery()
+            bindData(query, params)
+    
+            def criteria = Race.createCriteria()
+    
+            def results = criteria {
+                and {
+                    like('city', '%' + query.city + '%')
+                    like('state', '%' + query.state + '%')
+                    if (query.distance) {
+                        switch (query.distanceOperator) {
+                            case RaceQuery.DistanceOperator.AT_LEAST:
+                                ge('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.EXACTLY:
+                                eq('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.AT_MOST:
+                                le('distance', query.distance)
+                                break
+                            default:
+                                log.error &quot;Found unexpected value for distance&quot;
+                                    + &quot; operator - ${query.distanceOperator}&quot;
+                        }
+                    }
+                    // Add 1 day (24 hours) to the max date.  If user selects a max
+                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but
+                    // the user will want any events occurring thru Jan 1st 23:59.
+                    between('startDateTime', query.minDate, query.maxDate + 1)
+                }
+            }
+    
+            render(view:'searchresults', model:[ raceList: results.adaptee ])
+        }
+    }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/controllers/RaceController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
             
-class RegistrationController extends BaseController {
-    def beforeInterceptor = [action:this.&amp;auth, except:'register'] 
+class RegistrationController extends BaseController { 
+    def beforeInterceptor = [action:this.&amp;auth, except:'register']
     
     def index = { redirect(action:list,params:params) }
 
@@ -49,7 +49,7 @@ class RegistrationController extends BaseController {
         if(registration) {
              registration.properties = params
             if(registration.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:registration.id)
             }
             else {
@@ -72,7 +72,7 @@ class RegistrationController extends BaseController {
         def registration = new Registration()
         registration.properties = params
         if(registration.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot;                 
             redirect(action:show,id:registration.id)
         }
         else {
@@ -80,6 +80,7 @@ class RegistrationController extends BaseController {
         }
     }
 
+
     def register = { 
         def registration = new Registration() 
         registration.properties = params 
@@ -90,8 +91,7 @@ class RegistrationController extends BaseController {
         } 
         else { 
             if(registration.save()) { 
-                flash.message =  
-                    &quot;Successfully registered for ${registration.race.name}&quot; 
+                flash.message = &quot;Successfully registered for ${registration.race.name}&quot; 
                 redirect(controller:'race',action:'search') 
             } 
             else { 
@@ -99,5 +99,5 @@ class RegistrationController extends BaseController {
                 return ['registration':registration,'race':race] 
             } 
         } 
-    } 
+    }  
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/controllers/RegistrationController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
             
 class UserController extends BaseController { 
     def beforeInterceptor = [action:this.&amp;auth, except:['login', 'logout']] 
-    
+
     def index = { redirect(action:list,params:params) }
 
     // the delete, save and update actions only</diff>
      <filename>racetrack_ch6/grails-app/controllers/UserController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Race {  
+class Race { 
     String name 
     Date startDateTime 
     String city 
@@ -7,16 +7,16 @@ class Race {
     Float cost 
     Integer maxRunners = 100000 
      
-    static hasMany = [registrations:Registration]  
+    static hasMany = [registrations:Registration]
     
     static constraints = { 
-        name(maxLength:50,blank:false) 
-        startDateTime(validator: {return (it &gt; new Date())})  
-        city(maxLength:30,blank:false) 
+        name(maxSize:50,blank:false) 
+        startDateTime(validator: {return (it &gt; new Date())}) 
+        city(maxSize:30,blank:false) 
         state(inList:['GA', 'NC', 'SC', 'VA'],blank:false) 
         distance(min:3.1f,max:100f) 
         cost(min:0f,max:999.99f) 
-    }
+    } 
     
-    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot;}     
-}
\ No newline at end of file
+    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot; }
+}	</diff>
      <filename>racetrack_ch6/grails-app/domain/Race.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Registration  {  
+class Registration { 
     Race race 
     String name 
     Date dateOfBirth 
@@ -6,19 +6,17 @@ class Registration  {
     String postalAddress 
     String emailAddress 
     Date createdAt = new Date() 
-    
+
     static belongsTo = Race 
-    
-    static optionals = [&quot;postalAddress&quot; ]  
-    
+
     static constraints = { 
-        name(maxLength:50,blank:false) 
+        name(maxSize:50,blank:false) 
         dateOfBirth(nullable:false) 
         gender(inList:[&quot;M&quot;, &quot;F&quot;]) 
-        postalAddress(maxLength:255) 
-        emailAddress(maxLength:50,email:true) 
+        postalAddress(nullable:true,maxSize:255) 
+        emailAddress(maxSize:50,email:true) 
         race(nullable:false) 
     } 
-
-  String toString() {&quot;${this.name} : ${this.emailAddress}&quot;}         
-}
\ No newline at end of file
+    
+    String toString(){&quot;${this.name}:${this.emailAddress}&quot;}         
+}	</diff>
      <filename>racetrack_ch6/grails-app/domain/Registration.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@ class User {
     String password 
  
     static constraints = { 
-        userId(length:6..8,unique:true) 
-        password(length:6..8) 
+        userId(size:6..8,unique:true) 
+        password(size:6..8) 
     } 
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/domain/User.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,29 +1,28 @@
 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.message=Property [{0}] of class [{1}] is not a valid [{2}].
+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.length.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
-default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
 default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
-default.invalid.max.length.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
-default.invalid.min.length.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{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.not.editable.message=Property [{0}] of class [{1}] with value [{2}] cannot be changed from [{3}] 
 
-race.name.blank=Please enter a name for this race 
+default.paginate.prev=Previous
+default.paginate.next=Next
+
+race.name.blank=Please enter a name for this race
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles 
 race.startDateTime.validator.invalid=Please enter a future date and time
 race.city.blank=Please enter a city for this race
-race.city.maxLength.exceeded=Please limit the city name to a maximum length of {3} characters
+race.city.maxSize.exceeded=Please limit the city name to a maximum length of {3} characters
 race.distance.nullable=Please enter a valid distance
 race.distance.min.notmet=Please enter a valid distance no fewer than {3} miles
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles
@@ -32,8 +31,8 @@ race.cost.min.notmet=Please enter a valid cost of at least ${3}
 race.cost.max.exceeded=Please enter a valid cost no more than ${3}
 
 registration.name.blank=Please enter a name
-registration.name.maxLength.exceeded=Please limit the name to a maximum length of {3} characters
-registration.postalAddress.maxLength.exceeded=Please limit the postal address to a maximum length of {3} characters
+registration.name.maxSize.exceeded=Please limit the name to a maximum length of {3} characters
+registration.postalAddress.maxSize.exceeded=Please limit the postal address to a maximum length of {3} characters
 registration.emailAddress.blank=Please enter an e-mail address
-registration.emailAddress.maxLength.exceeded=Please limit the e-mail address to a maximum length of {3} characters
+registration.emailAddress.maxSize.exceeded=Please limit the e-mail address to a maximum length of {3} characters
 registration.emailAddress.email.invalid=Please enter a valid e-mail address
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/i18n/messages.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,18 +1,22 @@
 &lt;g:if test=&quot;${!session.userId}&quot;&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;login&quot;&gt;Log in&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;login&quot;&gt;Log 
+in&lt;/g:link&gt; 
     &lt;/span&gt; 
 &lt;/g:if&gt; 
 &lt;g:else&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
         &lt;g:link controller=&quot;race&quot; action=&quot;list&quot;&gt; 
-            Manage Races &amp; Registrations 
+            Manage Races &amp;amp; Registrations 
         &lt;/g:link&gt; 
     &lt;/span&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;list&quot;&gt;Manage Administrators&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;list&quot;&gt;Manage Administrators 
+         &lt;/g:link&gt; 
     &lt;/span&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;logout&quot;&gt;Log out&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;logout&quot;&gt; 
+            Log out 
+        &lt;/g:link&gt; 
     &lt;/span&gt; 
 &lt;/g:else&gt; </diff>
      <filename>racetrack_ch6/grails-app/views/_adminmenubar.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -16,4 +16,4 @@
             &lt;/tr&gt; 
         &lt;/table&gt; 
     &lt;/body&gt; 
-&lt;/html&gt; 
+&lt;/html&gt; 
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/views/layouts/public.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -28,19 +28,19 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/race/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -31,19 +31,19 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='registrations'&gt;Registrations:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'registrations','errors')}'&gt;&lt;ul&gt;
     &lt;g:each var='r' in='${race?.registrations?}'&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/race/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New Race&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt; 
-                &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
+                    &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
             &lt;/span&gt; 
             &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
@@ -24,17 +24,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Start Date Time&lt;/th&gt;
-                                      
-                        &lt;th&gt;City&lt;/th&gt;
-                                      
-                        &lt;th&gt;State&lt;/th&gt;
-                                      
-                        &lt;th&gt;Distance&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;startDateTime&quot; title=&quot;Start Date Time&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;city&quot; title=&quot;City&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;state&quot; title=&quot;State&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;distance&quot; title=&quot;Distance&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/race/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,14 +1,15 @@
 &lt;html&gt; 
     &lt;head&gt; 
-        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt; 
+        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;  
+       charset=UTF-8&quot;/&gt; 
         &lt;meta name=&quot;layout&quot; content=&quot;public&quot; /&gt; 
         &lt;title&gt;Search for Races&lt;/title&gt; 
     &lt;/head&gt; 
     &lt;body&gt; 
-        &lt;div class=&quot;nav&quot;&gt; 
-            &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
-        &lt;/div&gt;
-        &lt;div class=&quot;body&quot;&gt; 
+      &lt;div class=&quot;nav&quot;&gt; 
+         &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
+      &lt;/div&gt; 
+      &lt;div class=&quot;body&quot;&gt; 
          &lt;h1&gt;Search for Races&lt;/h1&gt; 
          &lt;g:if test=&quot;${flash.message}&quot;&gt; 
              &lt;div class=&quot;message&quot;&gt;${flash.message}&lt;/div&gt; 
@@ -30,34 +31,37 @@
                        &lt;label for='state'&gt;State:&lt;/label&gt; 
                    &lt;/td&gt; 
                    &lt;td valign='top' class='value'&gt; 
-                       &lt;g:select name='state' from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
+                       &lt;g:select name='state'  
+                   from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
                       &lt;/g:select&gt; 
                    &lt;/td&gt; 
                &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='date'&gt;Date:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         between 
-                         &lt;g:datePicker name='minDate' precision='day' /&gt; 
-                         and 
-                         &lt;g:datePicker name='maxDate' precision='day' value='${new Date().plus(365*2)}'/&gt; 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         &lt;select name='distanceOperator' &gt; 
-                             &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
-                             &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
-                             &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
-                         &lt;/select&gt; 
-                         &lt;input type='text' name='distance' size='5'&gt;&lt;/input&gt; mi 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt;               
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='date'&gt;Date:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     between 
+                     &lt;g:datePicker name='minDate' precision='day' /&gt; 
+                     and 
+                     &lt;g:datePicker name='maxDate' precision='day'  
+                  value='${new Date().plus(365*2)}'/&gt; 
+                 &lt;/td&gt; 
+             &lt;/tr&gt; 
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     &lt;select name='distanceOperator' &gt; 
+                         &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
+                         &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
+                         &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
+                     &lt;/select&gt; 
+                     &lt;input type='text' name='distance' size='5'&gt; 
+             &lt;/input&gt; mi 
+                 &lt;/td&gt; 
+             &lt;/tr&gt;
             &lt;/table&gt; 
             &lt;/div&gt; 
             &lt;div class=&quot;buttons&quot;&gt; </diff>
      <filename>racetrack_ch6/grails-app/views/race/search.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -84,4 +84,4 @@
             &lt;/div&gt; 
         &lt;/div&gt; 
     &lt;/body&gt; 
-&lt;/html&gt;
\ No newline at end of file
+&lt;/html&gt; </diff>
      <filename>racetrack_ch6/grails-app/views/race/searchresults.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
   
 &lt;html&gt;
     &lt;head&gt;
-         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
+         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;  
          &lt;g:javascript library=&quot;racetrack&quot; /&gt;          
           &lt;meta name=&quot;layout&quot; content=&quot;main&quot; /&gt;
          &lt;title&gt;Show Race&lt;/title&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/race/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -25,10 +25,7 @@
                &lt;div class=&quot;dialog&quot;&gt;
                 &lt;table&gt;
                     &lt;tbody&gt;
-
-                       
-                       
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -36,12 +33,10 @@
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='createdAt'&gt;Created At:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'createdAt','errors')}'&gt;&lt;g:datePicker name='createdAt' value=&quot;${registration?.createdAt}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
-                       
                     &lt;/tbody&gt;
                &lt;/table&gt;
                &lt;/div&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/registration/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -31,7 +31,7 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -39,7 +39,7 @@
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -51,7 +51,7 @@
 
                &lt;div class=&quot;buttons&quot;&gt;
                      &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Update&quot; /&gt;&lt;/span&gt;
-                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/div&gt;
             &lt;/g:form&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/registration/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -21,17 +21,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Date Of Birth&lt;/th&gt;
-                                      
-                        &lt;th&gt;Gender&lt;/th&gt;
-                                      
-                        &lt;th&gt;Postal Address&lt;/th&gt;
-                                      
-                        &lt;th&gt;Email Address&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;dateOfBirth&quot; title=&quot;Date Of Birth&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;gender&quot; title=&quot;Gender&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;postalAddress&quot; title=&quot;Postal Address&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;emailAddress&quot; title=&quot;Email Address&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/registration/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -5,10 +5,10 @@
     &lt;title&gt;Register&lt;/title&gt; 
   &lt;/head&gt; 
   &lt;body&gt; 
+  &lt;div class=&quot;body&quot;&gt; 
       &lt;div class=&quot;nav&quot;&gt; 
           &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
       &lt;/div&gt;
-      &lt;div class=&quot;body&quot;&gt; 
       &lt;h1&gt;Register for ${race.name} &lt;/h1&gt; 
       &lt;em&gt;Start Date: 
         &lt;g:formatDate date=&quot;${race.startDateTime}&quot; format=&quot;EEE, MMM d, yyyy&quot;/&gt; 
@@ -89,4 +89,4 @@
       &lt;/g:form&gt; 
     &lt;/div&gt; 
   &lt;/body&gt; 
-&lt;/html&gt; 
\ No newline at end of file
+&lt;/html&gt; </diff>
      <filename>racetrack_ch6/grails-app/views/registration/register.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -78,7 +78,7 @@
                &lt;g:form controller=&quot;registration&quot;&gt;
                  &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;${registration?.id}&quot; /&gt;
                  &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Edit&quot; /&gt;&lt;/span&gt;
-                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/g:form&gt;
            &lt;/div&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/registration/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@
         &lt;div class=&quot;nav&quot;&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Create User&lt;/h1&gt;
@@ -27,9 +28,9 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/user/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+             &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Edit User&lt;/h1&gt;
@@ -33,9 +34,9 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                 &lt;/table&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/user/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@
         &lt;div class=&quot;nav&quot;&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;User List&lt;/h1&gt;
@@ -20,15 +21,14 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                   
-                                      
-                        &lt;th&gt;Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;User Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;Password&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+               
+                   	    &lt;g:sortableColumn property=&quot;id&quot; title=&quot;Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;userId&quot; title=&quot;User Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;password&quot; title=&quot;Password&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/user/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -44,4 +44,4 @@
             &lt;/g:form&gt; 
         &lt;/div&gt; 
     &lt;/body&gt; 
-&lt;/html&gt; 
+&lt;/html&gt; 
\ No newline at end of file</diff>
      <filename>racetrack_ch6/grails-app/views/user/login.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Show User&lt;/h1&gt;</diff>
      <filename>racetrack_ch6/grails-app/views/user/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,10 @@ import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
-class ApplicationTagLib {
+class ApplicationTagLib { 
+	
+	def grailsUrlMappingsHolder
+	
     /**
      * Creates a link to a resource, generally used as a method rather than a tag.
      *
@@ -33,7 +36,7 @@ class ApplicationTagLib {
      */
     def createLinkTo = { attrs -&gt;
          out &lt;&lt; grailsAttributes.getApplicationUri(request)
-         if(attrs['dir']) {
+         if(attrs['dir'] || attrs['dir'] == '') {
             out &lt;&lt; &quot;/${attrs['dir']}&quot;
          }
          if(attrs['file']) {
@@ -50,7 +53,7 @@ class ApplicationTagLib {
     def link = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;a href=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // process remaining attributes
@@ -59,7 +62,7 @@ class ApplicationTagLib {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -79,29 +82,47 @@ class ApplicationTagLib {
         if(attrs['url']) {
              attrs = attrs.remove('url')
         }
-        // if the current attribute null set the controller uri to the current controller
-        if(attrs[&quot;controller&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;controller&quot;)
-        }
-        else {
-           out &lt;&lt; grailsAttributes.getControllerUri(request)
-        }
-        if(attrs[&quot;action&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;action&quot;)
-        }
-        if(attrs[&quot;id&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;id&quot;)
-        }
-        if(attrs['params']) {
-            def pms = attrs.remove('params')
-            out &lt;&lt; '?'
-            def i = 0
-            pms.each { k,v -&gt;
-                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
-                if(++i &lt; pms.size())
-                   out &lt;&lt; '&amp;'
-            }
-        }
+                                                     
+		def controller = attrs.containsKey(&quot;controller&quot;) ? attrs.remove(&quot;controller&quot;) : grailsAttributes.getController(request).controllerName
+		def action = attrs.remove(&quot;action&quot;)
+        def id = attrs.remove(&quot;id&quot;)
+        def params = attrs.params ? attrs.remove('params') : [:]
+
+        def url
+		try {
+            if(id) params.id = id
+            def mapping = grailsUrlMappingsHolder?.getReverseMapping(controller,action,params)
+			params.controller = controller
+			if(action) params.action = action  
+            url = mapping?.createURL(params)
+		}        
+		finally {
+			params.remove('controller')
+			params.remove('action')          
+			params.remove('id')
+		}
+		if(url) {
+			out &lt;&lt; url
+		}             
+		else {
+            out &lt;&lt; '/' &lt;&lt; controller
+	        if(action) {
+	            out &lt;&lt; '/' &lt;&lt; action
+	        }
+	        if(id) {
+	            out &lt;&lt; '/' &lt;&lt; id
+	        }
+	        if(params) {
+	            out &lt;&lt; '?'
+	            def i = 0
+	            params.each { k,v -&gt;
+	                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
+	                if(++i &lt; params.size())
+	                   out &lt;&lt; '&amp;'
+	            }
+	        }			
+		}
+															
     }
 
 	/**
@@ -127,8 +148,8 @@ class ApplicationTagLib {
 				} 				
 			}
 		}
-		out &lt;&lt; '&gt;'
-		body()
+		out &lt;&lt; '&gt;'  
+		out &lt;&lt; body()
 		out &lt;&lt; &quot;&lt;/${attrs.name}&gt;&quot;			
 	}	
 }</diff>
      <filename>racetrack_ch6/plugins/core/grails-app/taglib/ApplicationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -16,6 +16,7 @@ import org.springframework.validation.Errors;
 import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
+import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
 
  /**
  *  A  tag lib that provides tags for working with form controls
@@ -33,7 +34,10 @@ class FormTagLib {
 	def textField = { attrs -&gt;
 		attrs.type = &quot;text&quot;  
 		attrs.tagName = &quot;textField&quot; 
-		field(attrs)
+		def result = field(attrs)
+		if(result) {     
+			out &lt;&lt; result
+		}
 	}
 	/**
 	 * Creates a hidden field
@@ -41,7 +45,7 @@ class FormTagLib {
 	def hiddenField = { attrs -&gt;
 		attrs.type = &quot;hidden&quot;
 		attrs.tagName = &quot;hiddenField&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * Creates a submit button
@@ -49,7 +53,7 @@ class FormTagLib {
 	def submitButton = { attrs -&gt;
 		attrs.type = &quot;submit&quot;
 		attrs.tagName = &quot;submitButton&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * A general tag for creating fields
@@ -84,7 +88,7 @@ class FormTagLib {
     void resolveAttributes(attrs)
     {
         if(!attrs.name &amp;&amp; !attrs.field) {
-            throwTagError(&quot;Tag [$tagName] is missing required attribute [name] or [field]&quot;)
+            throwTagError(&quot;Tag [${attrs.tagName}] is missing required attribute [name] or [field]&quot;)
         }
         attrs.remove('tagName')
 
@@ -121,7 +125,7 @@ class FormTagLib {
     def form = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;form action=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // default to post
@@ -133,26 +137,34 @@ class FormTagLib {
 
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        def bodyContent = body()
+		out &lt;&lt; bodyContent
 
         // close tag
         out &lt;&lt; &quot;&lt;/form&gt;&quot;
     }
     /**
      * Creates a submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmit value=&quot;Edit&quot; /&gt;
+     *  &lt;g:actionSubmit action=&quot;Edit&quot; value=&quot;Some label for editing&quot; /&gt;
      *
      */
     def actionSubmit = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;submit&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+    	if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
-        // process remaining attributes
+
+		// add action and value
+		def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    	
+    	out &lt;&lt; &quot;&lt;input type=\&quot;submit\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+    	
+    	// process remaining attributes
         outputAttributes(attrs)
 
         // close tag
@@ -161,22 +173,30 @@ class FormTagLib {
     }
     /**
      * Creates a an image submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmitImage src=&quot;/images/submitButton.gif&quot; action=&quot;Edit&quot; /&gt;
      *
      */
     def actionSubmitImage = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;image&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+        if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
+        
+        // add action and value
+        def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    
+        out &lt;&lt; &quot;&lt;input type=\&quot;image\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+
+		// add image src        
         def src = attrs.remove('src')
         if(src) {
              out &lt;&lt; &quot;src=\&quot;${src}\&quot; &quot;
         }
+
         // process remaining attributes
         outputAttributes(attrs)
 
@@ -201,6 +221,8 @@ class FormTagLib {
 
         def value = (attrs['value'] ? attrs['value'] : xdefault)
         def name = attrs['name']
+        def id = attrs['id'] ? attrs['id'] : name
+
 		def noSelection = attrs['noSelection']
 		if (noSelection != null)
 		{
@@ -253,7 +275,7 @@ class FormTagLib {
 
         // create day select
         if (precision &gt;= PRECISION_RANKINGS[&quot;day&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_day\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_day\&quot; id=\&quot;${id}_day\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -272,7 +294,7 @@ class FormTagLib {
 
         // create month select
         if (precision &gt;= PRECISION_RANKINGS[&quot;month&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_month\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_month\&quot; id=\&quot;${id}_month\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -294,7 +316,7 @@ class FormTagLib {
 
         // create year select
         if (precision &gt;= PRECISION_RANKINGS[&quot;year&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_year\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_year\&quot; id=\&quot;${id}_year\&quot;&gt;&quot;
 
             if (noSelection) {
     			renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -313,7 +335,7 @@ class FormTagLib {
 
         // do hour select
         if (precision &gt;= PRECISION_RANKINGS[&quot;hour&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot; id=\&quot;${id}_hour\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -338,7 +360,7 @@ class FormTagLib {
 
         // do minute select
         if (precision &gt;= PRECISION_RANKINGS[&quot;minute&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot; id=\&quot;${id}_minute\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -360,7 +382,7 @@ class FormTagLib {
 	def renderNoSelectionOption = { noSelectionKey, noSelectionValue, value -&gt;
 		// If a label for the '--Please choose--' first item is supplied, write it out
         out &lt;&lt; '&lt;option value=&quot;' &lt;&lt; (noSelectionKey == null ? &quot;&quot; : noSelectionKey) &lt;&lt; '&quot;'
-        if(noSelectionKey == value) {
+        if(noSelectionKey.equals(value)) {
             out &lt;&lt; ' selected=&quot;selected&quot; '
         }
         out &lt;&lt; '&gt;' &lt;&lt; noSelectionValue.encodeAsHTML() &lt;&lt; '&lt;/option&gt;'
@@ -388,7 +410,7 @@ class FormTagLib {
         }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -405,7 +427,7 @@ class FormTagLib {
         attrs['optionValue'] = { &quot;${it.language}, ${it.country},  ${it.displayName}&quot; }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -425,7 +447,7 @@ class FormTagLib {
 		   	attrs.value = null
 		}
         // invoke generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -436,11 +458,15 @@ class FormTagLib {
      * &lt;g:select name=&quot;user.company.id&quot; from=&quot;${Company.list()}&quot; value=&quot;${user?.company.id}&quot; optionKey=&quot;id&quot; /&gt;
      */
     def select = { attrs -&gt;
+	    def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request)
+
         def from = attrs.remove('from')
         def keys = attrs.remove('keys')
         def optionKey = attrs.remove('optionKey')
         def optionValue = attrs.remove('optionValue')
         def value = attrs.remove('value')
+        def valueMessagePrefix = attrs.remove('valueMessagePrefix')
 		def noSelection = attrs.remove('noSelection')
         if (noSelection != null) {
             noSelection = noSelection.entrySet().iterator().next()
@@ -461,20 +487,21 @@ class FormTagLib {
         // create options from list
         if(from) {
             from.eachWithIndex { el,i -&gt;
+            	def keyValue = null
                 out &lt;&lt; '&lt;option '
                 if(keys) {
-                    out &lt;&lt; 'value=&quot;' &lt;&lt; keys[i] &lt;&lt; '&quot; '
-                    if(keys[i] == value) {
+                    keyValue = keys[i]
+                    out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
-               else if(optionKey) {
-                    def keyValue = null
+                else if(optionKey) {
                     if(optionKey instanceof Closure) {
                         keyValue = optionKey(el)
-                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                        out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
-                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getGrailsDomainClass(el.getClass().name)) {
+                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, el.getClass().name)) {
                         keyValue = el.ident()
                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
@@ -488,8 +515,9 @@ class FormTagLib {
                     }
                 }
                 else {
-                    out &lt;&lt; &quot;value=\&quot;${el}\&quot; &quot;
-                    if(el == value) {
+                	keyValue = el
+                    out &lt;&lt; &quot;value=\&quot;${keyValue}\&quot; &quot;
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
@@ -502,6 +530,19 @@ class FormTagLib {
                         out &lt;&lt; el.properties[optionValue].toString().encodeAsHTML()
                     }
                 }
+                else if(valueMessagePrefix) {
+                	def message = messageSource.getMessage(&quot;${valueMessagePrefix}.${keyValue}&quot;, null, null, locale)
+                	if(message) {
+                		out &lt;&lt; message.encodeAsHTML()
+                	}
+                	else if (keyValue) {
+                		out &lt;&lt; keyValue.encodeAsHTML()
+                	}
+					else {
+        	            def s = el.toString()
+    	                if(s) out &lt;&lt; s.encodeAsHTML()
+	                }
+                }
                 else {
                     def s = el.toString()
                     if(s) out &lt;&lt; s.encodeAsHTML()
@@ -554,6 +595,6 @@ class FormTagLib {
         outputAttributes(attrs)
 
         // close the tag, with no body
-        out &lt;&lt; ' &gt;&lt;/input&gt;'
+        out &lt;&lt; ' /&gt;'
      }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch6/plugins/core/grails-app/taglib/FormTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ class JavascriptTagLib  {
 		}
 		else {
 			out.println '&lt;script type=&quot;text/javascript&quot;&gt;'
-				body()
+				out &lt;&lt; body()
 			out.println '&lt;/script&gt;'
 		}
 	}
@@ -137,15 +137,15 @@ class JavascriptTagLib  {
     /**
      * A link to a remote uri that used the prototype library to invoke the link via ajax
      */
-    def remoteLink = { attrs, body -&gt;
+    def remoteLink = { attrs, body -&gt;  
        out &lt;&lt; &quot;&lt;a href=\&quot;&quot;    
 
        def cloned = deepClone(attrs)
-	   createLink(cloned)               
+	   out &lt;&lt; createLink(cloned)               
 
 	   out &lt;&lt; &quot;\&quot; onclick=\&quot;&quot;
         // create remote function
-        remoteFunction(attrs)   
+        out &lt;&lt; remoteFunction(attrs)   
 		attrs.remove('url')
         out &lt;&lt; &quot;return false;\&quot; &quot;
         // process remaining attributes
@@ -154,7 +154,7 @@ class JavascriptTagLib  {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -180,7 +180,7 @@ class JavascriptTagLib  {
 		else {
     		attrs.params = &quot;'${paramName}='+this.value&quot;			
 		}
-		remoteFunction(attrs)
+		out &lt;&lt; remoteFunction(attrs)
 		attrs.remove('params')
 		out &lt;&lt; &quot;\&quot;&quot;   
 		attrs.remove('url')
@@ -208,16 +208,16 @@ class JavascriptTagLib  {
 		// prepare form settings
 		prepareAjaxForm(p,attrs)
         
-        def params = [  onsubmit:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onsubmit:remoteFunction(attrs) + 'return false',
 					    method: (attrs.method? attrs.method : 'POST' ),
-					    action: (attrs.action? attrs.action : TagLibUtil.outToString(createLink,url))		                 
+					    action: (attrs.action? attrs.action : createLink(url))		                 
 		             ]
 		attrs.remove('url')		             
 	    params.putAll(attrs)
 		if(params.name &amp;&amp; !params.id)
 			params.id = params.name
-	    withTag(name:'form',attrs:params) {
-			body()   
+	    out &lt;&lt; withTag(name:'form',attrs:params) {
+			out &lt;&lt; body()   
 	    }		
     }
 
@@ -230,7 +230,7 @@ class JavascriptTagLib  {
 		// prepare form settings 
 		attrs.forSubmitTag = &quot;.form&quot;
 		prepareAjaxForm(p,attrs)    
-        def params = [  onclick:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onclick:remoteFunction(attrs) + 'return false',
 					    type: 'button',
 					    name: attrs.remove('name'),
 					    value: attrs.remove('value'), 
@@ -238,8 +238,8 @@ class JavascriptTagLib  {
 					    'class':attrs.remove('class')
 		             ]
 		             
-		withTag(name:'input', attrs:params) {
-			body()	
+		out &lt;&lt; withTag(name:'input', attrs:params) {
+			out &lt;&lt; body()	
 		}
     }
 	
@@ -275,7 +275,7 @@ class JavascriptTagLib  {
 			def sw = new StringWriter()
 			out = new PrintWriter(out)
 			// invoke body
-			body()
+			out &lt;&lt; body()
 			// restore out
 			out = tmp
 			js = sw.toString()
@@ -357,10 +357,10 @@ class PrototypeProvider implements JavascriptProvider {
 		
 		def pms = attrs.remove('params')   
 		if(attrs.url) {
-			taglib.createLink(attrs.url)			
+			out &lt;&lt; taglib.createLink(attrs.url)			
 		}                              
 		else {
-			taglib.createLink(attrs)			
+			out &lt;&lt; taglib.createLink(attrs)			
 		}
 
 		
@@ -415,6 +415,7 @@ class PrototypeProvider implements JavascriptProvider {
 	                    case 'true': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case 'false': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case ~/\s*function(\w*)\s*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
+	                    case ~/Insertion\..*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    default:ajaxOptions &lt;&lt; &quot;${k}:'${v}'&quot;; break;
 	                 }            	
             	}
@@ -441,10 +442,10 @@ class YahooProvider implements JavascriptProvider {
 		out &lt;&lt; &quot;YAHOO.util.Connect.asyncRequest('${method}','&quot;
 				
 		if(attrs.url) {
-			taglib.createLink(attrs.url)
+			out &lt;&lt; taglib.createLink(attrs.url)
 		}
 		else {
-			taglib.createLink(attrs)
+			out &lt;&lt; taglib.createLink(attrs)
 		}		
 		attrs.remove('url')
 		out &lt;&lt; &quot;',&quot;
@@ -504,7 +505,7 @@ class DojoProvider implements JavascriptProvider {
 		}		
 		 out &lt;&lt; 'dojo.io.bind({url:\''
 
-		 taglib.createLink(attrs) 
+		 out &lt;&lt; taglib.createLink(attrs) 
 		attrs.remove('params')
 		 out &lt;&lt; '\',load:function(type,data,evt) {'
 	    if(attrs.onLoaded) {</diff>
      <filename>racetrack_ch6/plugins/core/grails-app/taglib/JavascriptTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,6 +25,7 @@ import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
 class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants {
+	def out // to facilitate testing
 
     protected getPage() {
     	return request[PAGE]
@@ -91,7 +92,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 				}
 			}
 			if(invokeBody) {
-				body();	
+				out &lt;&lt; body()
 			}
 		}
 	}
@@ -134,54 +135,183 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         if(attrs.total == null)
             throwTagError(&quot;Tag [paginate] is missing required attribute [total]&quot;)
 		
-		def mkp = new groovy.xml.MarkupBuilder(out)
+		def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request) 
+		
 		def total = attrs.total.toInteger()
-		def max = params.max?.toInteger()
-		def offset = params.offset?.toInteger() 
 		def action = (attrs.action? attrs.action : 'list')
-		def breadcrumb = true
-		if(attrs.breadcrumb) breadcrumb = Boolean.valueOf(attrs.breadcrumb)
-			
+		def offset = params.offset?.toInteger()
+		def max = params.max?.toInteger()
+		def maxsteps = (attrs.maxsteps ? attrs.maxsteps.toInteger() : 10)
+
+        if(attrs.breadcrumb) {
+			log.warn(&quot;Tag [paginate] includes the [breadcrumb] attribute. This attribute is deprecated and will be removed in the future. Please update your code to use the [maxsteps] attribute instead.&quot;)
+		}
+
+		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)			
 		if(!max) max = (attrs.max ? attrs.max.toInteger() : 10)
-		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)
 		
-		def linkParams = [offset:offset-max,max:max]
-		def linkTagAttrs = ['class':'prevLink',action:action]
+		def linkParams = [offset:offset - max, max:max]
+		if(params.sort) linkParams.sort = params.sort
+		if(params.order) linkParams.order = params.order
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		def linkTagAttrs = [action:action]
 		if(attrs.controller) {
 			linkTagAttrs.controller = attrs.controller	
 		}
 		if(attrs.id) {
 			linkTagAttrs.id = attrs.id	
 		}
-		if(attrs.params)linkParams.putAll(attrs.params)
 		linkTagAttrs.params = linkParams
-	
-		def combined = max + offset
-		if(offset &gt; 0) {			
-			link(linkTagAttrs.clone(),{out&lt;&lt; (attrs.prev? attrs.prev : 'Previous' ) })
+		
+		// determine paging variables
+		def steps = maxsteps &gt; 0
+		int currentstep = (offset / max) + 1
+		int firststep = 1
+		int laststep = Math.round(Math.ceil(total / max))
+			
+		// display previous link when not on firststep
+		if(currentstep &gt; firststep) {
+			linkTagAttrs.class = 'prevLink'
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.prev ? attrs.prev : messageSource.getMessage('default.paginate.prev', null, 'Previous', locale))
+			 }
 		}
 		
-		if(total &gt; max) {
-			linkTagAttrs.'class' = 'step'
-			if(breadcrumb) {
-				def j = 0
-				0.step(total,max) { i -&gt;
-					if(offset == i) {
-						mkp.a('class':'step',&quot;${++j}&quot;)	
-					}
-					else {
-						linkParams.offset=i
-						link(linkTagAttrs.clone(),{out&lt;&lt;++j})	
-					}
-				}			
+		// display steps when steps are enabled and laststep is not firststep
+		if(steps &amp;&amp; laststep &gt; firststep) {
+			linkTagAttrs.class = 'step'
+
+			// determine begin and endstep paging variables
+			int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
+			int endstep = currentstep + Math.round(maxsteps / 2) - 1
+			
+			if(beginstep &lt; firststep) {
+				beginstep = firststep
+				endstep = maxsteps
+			}
+			if(endstep &gt; laststep) {
+				beginstep = laststep - maxsteps + 1
+				if(beginstep &lt; firststep) {
+					beginstep = firststep
+				}
+				endstep = laststep
+			}
+
+			// display firststep link when beginstep is not firststep
+			if(beginstep &gt; firststep) {
+				linkParams.offset = 0
+				out &lt;&lt; link(linkTagAttrs.clone()) {firststep.toString()}
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+			}
+
+			// display paginate steps
+			(beginstep..endstep).each { i -&gt;
+				if(currentstep == i) {
+					out &lt;&lt; &quot;&lt;span class=\&quot;currentStep\&quot;&gt;${i}&lt;/span&gt;&quot;
+				}
+				else {
+					linkParams.offset = (i - 1) * max
+					out &lt;&lt; link(linkTagAttrs.clone()) {i.toString()}
+				}
+			}	
+			
+			// display laststep link when endstep is not laststep
+			if(endstep &lt; laststep) {
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+				linkParams.offset = (laststep -1) * max
+				out &lt;&lt; link(linkTagAttrs.clone()) { laststep.toString() }
+			}		
+		}
+		
+		// display next link when not on laststep
+		if(currentstep &lt; laststep) {	
+			linkTagAttrs.class = 'nextLink'			
+			linkParams.offset = offset + max
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.next ? attrs.next : messageSource.getMessage('default.paginate.next', null, 'Next', locale))
 			}			
 		}
-		linkParams.offset = offset+max
-		if(combined &lt; total) {	
-			linkTagAttrs.'class'='nextLink'			
-			link(linkTagAttrs,{out&lt;&lt; (attrs.'next'? attrs.'next' : 'Next' )})			
+
+	}
+
+	/**
+	 * Renders a sortable column to support sorting in list views
+	 *
+	 * Attributes:
+	 *
+	 * property - name of the property relating to the field
+	 * defaultOrder (optional) - default order for the property; choose between asc (default if not provided) and desc
+	 * title (optional*) - title caption for the column
+	 * titleKey (optional*) - title key to use for the column, resolved against the message source
+	 * params (optional) - a map containing request parameters
+	 *
+	 * Attribute title or titleKey is required. When both attributes are specified then titleKey takes precedence,
+	 * resulting in the title caption to be resolved against the message source. In case when the message could
+	 * not be resolved, the title will be used as title caption. 
+	 *
+	 * Examples:
+	 *
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; style=&quot;width: 200px&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; titleKey=&quot;book.title&quot; /&gt;	 
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; titleKey=&quot;book.releaseDate&quot; /&gt;
+	 */
+	def sortableColumn = { attrs -&gt;
+
+		if(!attrs.property)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [property]&quot;) 
+		
+		if(!attrs.title &amp;&amp; !attrs.titleKey)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [title] or [titleKey]&quot;)
+
+		def property = attrs.remove(&quot;property&quot;)
+		def action = attrs.action ? attrs.remove(&quot;action&quot;) : &quot;list&quot;
+		
+		def defaultOrder = attrs.remove(&quot;defaultOrder&quot;)
+		if(defaultOrder != &quot;desc&quot;) defaultOrder = &quot;asc&quot;
+
+		// current sorting property and order
+		def sort = params.sort
+		def order = params.order
+
+		// add sorting property and params to link params
+		def linkParams = [sort:property]
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		// determine and add sorting order for this column to link params
+		attrs.class = &quot;sortable&quot;
+		if(property == sort) {
+			attrs.class = attrs.class + &quot; sorted &quot; + order
+			if(order == &quot;asc&quot;) {
+				linkParams.order = &quot;desc&quot;
+			}
+			else {
+				linkParams.order = &quot;asc&quot;
+			}
+		}
+		else {
+			linkParams.order = defaultOrder
+		}
+
+		// determine column title
+		def title = attrs.remove(&quot;title&quot;)
+		def titleKey = attrs.remove(&quot;titleKey&quot;)
+		if(titleKey) {
+			if(!title) title = titleKey
+			def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+			def locale = RCU.getLocale(request)
+			title = messageSource.getMessage(titleKey, null, title, locale)
 		}
 
+		out &lt;&lt; &quot;&lt;th &quot;
+		// process remaining attributes
+		attrs.each { k, v -&gt;
+			out &lt;&lt; &quot;${k}=\&quot;${v.encodeAsHTML()}\&quot; &quot;
+		}
+		out &lt;&lt; &quot;&gt;${link(action:action, params:linkParams) { title }}&lt;/th&gt;&quot;
 	}
 
     /**
@@ -199,14 +329,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         def uri = grailsAttributes.getTemplateUri(attrs.template,request)
         def var = attrs['var']
 
-        def url = servletContext.getResource(uri)
-        if(!url)
-            throwTagError(&quot;No template found for name [${attrs.template}] in tag [render]&quot;)
-
-        def t = engine.createTemplate(  uri,
-                                        servletContext,
-                                        request,
-                                        response)
+        def t = engine.createTemplate( uri )
 
         if(attrs.model instanceof Map) {
             t.make( attrs.model ).writeTo(out)
@@ -246,14 +369,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 	        def engine = grailsAttributes.getPagesTemplateEngine()
 	        def uri = grailsAttributes.getTemplateUri(attrs.template,request)
 
-	        def url = servletContext.getResource(uri)
-	        if(!url)
-	            throwTagError(&quot;No template found for name [${attrs.template}] in tag [include]&quot;)
-
-	        def t = engine.createTemplate(  uri,
-	                                        servletContext,
-	                                        request,
-	                                        response)
+	        def t = engine.createTemplate(  uri )
 			
 			t.make().writeTo(out)
 		}</diff>
      <filename>racetrack_ch6/plugins/core/grails-app/taglib/RenderTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -152,7 +152,7 @@ class UITagLib {
 	 * &lt;g:richTextEditor name=&quot;editor&quot; height=&quot;400&quot; /&gt;
 	 */
 	def richTextEditor = { attrs -&gt;
-		withTag(name:'script',attributes:[type:'text/javascript']) {
+		out &lt;&lt; withTag(name:'script',attributes:[type:'text/javascript']) {
 			if(attrs.onComplete) {
 				out.println &quot;function FCKeditor_OnComplete( editorInstance ) {&quot;
 					out.println &quot;${attrs.onComplete}(editorInstance);&quot;					
@@ -162,24 +162,53 @@ class UITagLib {
 			var oFCKeditor = new FCKeditor( '${attrs.name}' ) ;
 			oFCKeditor.BasePath	 = \&quot;&quot;&quot;&quot;
 			if(attrs.basepath) {
-				createLinkTo(dir:attrs.basepath)
+				out &lt;&lt; createLinkTo(dir:attrs.basepath)
 			}
 			else {
-				createLinkTo(dir:&quot;fckeditor/&quot;)
+			    out &lt;&lt; createLinkTo(dir:&quot;fckeditor/&quot;)
 			}
 			out.println '&quot;;'
 			if(attrs.toolbar) {
 				out &lt;&lt; &quot;oFCKeditor.ToolbarSet	 = '${attrs.toolbar}';&quot; 	
-			}			
+			}
+			// add width support
+			if(attrs.width)			
+				out.println &quot;oFCKeditor.Width	= '${attrs.width}';&quot;
+			
 			if(attrs.height)			
-				out.println &quot;oFCKeditor.Height	= ${attrs.height};&quot;
+				out.println &quot;oFCKeditor.Height	= '${attrs.height}';&quot;
+			
+			// add skin support, values to choose: &quot;default&quot;, &quot;office2003&quot;, &quot;silver&quot;
+			if(attrs.skin)
+				out.println &quot;oFCKeditor.Config['SkinPath'] = 'skins/${attrs.skin}/';&quot;
+			
+			// check the browser compatibility when rendering the editor.  default value: true, values to choose: true, false, 
+			if(attrs.checkBrowser)
+				out.println &quot;oFCKeditor.CheckBrowser = ${attrs.checkBrowser};&quot;
+
+			// show error messages on errors while rendering the editor.   default value: true, values to choose: true, false
+			if(attrs.displayErrors)
+				out.println &quot;oFCKeditor.DisplayErrors = ${attrs.displayErrors};&quot;
+
+			// oFCKeditor.Config      AutoDetectLanguage:true/false, DefaultLanguage:'pt-BR' and so on
+			if(attrs.config) {
+				if (attrs.config instanceof Map) {
+					attrs.config.each { k, v -&gt;
+						out.println &quot;oFCKeditor.Config['$k'] = '$v';&quot;
+					}
+				} else {
+					throw new Exception(&quot;&quot;&quot;The format of config is not correct, it should be like &quot;[AutoDetectLanguage:false, DefaultLanguage:'pt-BR']&quot;   &quot;&quot;&quot;)
+				}
+			}
+
 			if(attrs.value) {
 				out &lt;&lt; &quot;oFCKeditor.Value	= \&quot;&quot;
-				escapeJavascript(Collections.EMPTY_MAP,attrs.value)
+			    out &lt;&lt; escapeJavascript(Collections.EMPTY_MAP,attrs.value)
 				out.println &quot;\&quot; ;&quot;
 			}
 			
-			out.println &quot;oFCKeditor.Create();&quot;			
+			out.println &quot;oFCKeditor.Create();&quot;	
+
 		}
 	}
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch6/plugins/core/grails-app/taglib/UITagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -32,9 +32,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def checkList = []
         if(model) {
-            checkList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors))
-            }
+            checkList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             checkList &lt;&lt; attrs['bean']
@@ -45,7 +43,7 @@ class ValidationTagLib {
 					if(ra) {
                         if(ra instanceof Errors)
                             checkList &lt;&lt; ra
-	                    else if ((ra.properties.errors) &amp;&amp; (ra.errors instanceof Errors)) {
+	                    else if (ra.properties?.errors instanceof Errors) {
                             checkList &lt;&lt; ra
 						}
 					}
@@ -55,23 +53,29 @@ class ValidationTagLib {
 
         for(i in checkList) {
             def errors = null
-            if(i instanceof Errors) {
+            if (i instanceof Errors) {
                errors = i
             }
-            else {
-				if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
-	                if (i.hasErrors())
-	                    errors = i.errors
-	            }
+            else {       
+				try {
+					if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
+		                if (i.hasErrors())
+		                    errors = i.errors
+		            }
+					
+				}   
+				catch(MissingPropertyException mpe) {
+					// ignore
+				}
 			}
             if(errors) {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
-                        body()
+                        out &lt;&lt; body()
                     }
                 }
                 else {
-                    body()
+                    out &lt;&lt; body()
                 }
             }
         }
@@ -84,9 +88,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def errorList = []
         if(model) {
-            errorList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors)) 
-            }
+            errorList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             errorList &lt;&lt; attrs['bean']
@@ -95,9 +97,9 @@ class ValidationTagLib {
             request.attributeNames.each {
                 def ra = request[it]
                 if(ra) {
-                    if(ra instanceof Errors)
+                    if (ra instanceof Errors)
                         errorList &lt;&lt; ra
-                    else if ((ra.errors != null) &amp;&amp; (ra.errors instanceof Errors)) {
+                    else if (ra.properties?.errors instanceof Errors) {
                         errorList &lt;&lt; ra
 					}
                 }
@@ -119,13 +121,13 @@ class ValidationTagLib {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
                         errors.getFieldErrors( attrs[&quot;field&quot;] ).each {
-                            body(it)
+                            out &lt;&lt; body(it)
                         }
                     }
                 }
                 else {
                     errors.allErrors.each {
-                        body( it )
+                        out &lt;&lt; body( it )
                     }
                 }
             }
@@ -141,9 +143,9 @@ class ValidationTagLib {
 
         if(renderAs == 'list') {
             out &lt;&lt; &quot;&lt;ul&gt;&quot;
-            eachError(attrs, {
+            out &lt;&lt; eachError(attrs, {
                 out &lt;&lt; &quot;&lt;li&gt;&quot;
-                message(error:it)
+                out &lt;&lt; message(error:it)
                 out &lt;&lt; &quot;&lt;/li&gt;&quot;
               }
             )
@@ -219,7 +221,7 @@ class ValidationTagLib {
         }
 
         def app = grailsAttributes.getGrailsApplication()
-        def dc = app.getGrailsDomainClass(againstClass)
+        def dc = app.getDomainClass(againstClass)
 
         if(!dc)
             throwTagError(&quot;Tag [validate] could not find a domain class to validate against for name [${againstClass}]&quot;)</diff>
      <filename>racetrack_ch6/plugins/core/grails-app/taglib/ValidationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ class URLCodec {
     }
 
     static decode = { obj -&gt;
-        URLEncoder.decode(obj.toString(), URLCodec.getEncoding())
+        URLDecoder.decode(obj.toString(), URLCodec.getEncoding())
     }
 
 	private static def getEncoding() {</diff>
      <filename>racetrack_ch6/plugins/core/grails-app/utils/URLCodec.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch6/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,9 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 
-&lt;beans&gt;
 	&lt;bean id=&quot;grailsApplication&quot; class=&quot;org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean&quot;&gt;
 		&lt;description&gt;Grails application factory bean&lt;/description&gt;
 		&lt;property name=&quot;groovyFiles&quot;&gt;
@@ -25,7 +27,7 @@
         &lt;property name=&quot;pluginManager&quot; ref=&quot;pluginManager&quot; /&gt;
     &lt;/bean&gt;
 	
-    &lt;bean id=&quot;grailsResourceHolder&quot; singleton=&quot;false&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
+    &lt;bean id=&quot;grailsResourceHolder&quot; scope=&quot;prototype&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
         &lt;property name=&quot;resources&quot;&gt;
               &lt;value&gt;classpath*:**/grails-app/**/*.groovy&lt;/value&gt;
         &lt;/property&gt;</diff>
      <filename>racetrack_ch6/web-app/WEB-INF/applicationContext.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch6/web-app/WEB-INF/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,254 @@
     &lt;uri&gt;http://grails.codehaus.org/tags&lt;/uri&gt;
 
     &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var}
+        &lt;/description&gt;
+        &lt;name&gt;set&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovySetTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var} into the page context
+        &lt;/description&gt;
+        &lt;name&gt;def&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyDefTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical if tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;if&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical else tag as fallback if the if condition fails
+        &lt;/description&gt;
+        &lt;name&gt;else&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical elseif tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;elseif&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;
+        	Tag to loop over a collection while the test expression returns true
+        &lt;/description&gt;
+        &lt;name&gt;while&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyWhileTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;each&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyEachTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;findAll&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyFindAllTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to filter the elements to iterate over&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and collects the elements
+        	you want to work with&lt;/description&gt;
+        &lt;name&gt;collect&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyCollectTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to use to collect the elements. The
+        	expression must retur true to add the element to the
+        	collection&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and filters the elements
+        with a regular expression&lt;/description&gt;
+        &lt;name&gt;grep&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyGrepTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The regular expression to filter the element with. The
+        	filter is a simple Groovy Regex&lt;/description&gt;
+            &lt;name&gt;filter&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;A tag that attempts to render an input for a bean property
+        into an appropriate component based on the type. It uses the templates
+        defined in &quot;grails-app/views/scaffolding&quot; to achieve this by looking up
+		the template by type.&lt;/description&gt;
+        &lt;name&gt;renderInput&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyRenderInputTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The Bean to render the input for&lt;/description&gt;
+            &lt;name&gt;bean&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The property of the bean to render input for&lt;/description&gt;
+            &lt;name&gt;property&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
         &lt;name&gt;link&lt;/name&gt;
         &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag&lt;/tag-class&gt;
         &lt;body-content&gt;JSP&lt;/body-content&gt;</diff>
      <filename>racetrack_ch6/web-app/WEB-INF/tld/grails.tld</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
 &lt;web-app version=&quot;2.4&quot;
          xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
          xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</diff>
      <filename>racetrack_ch6/web-app/WEB-INF/web.template.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/base/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/user/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
+&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;log4jRefreshInterval&lt;/param-name&gt;&lt;param-value&gt;1000&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;reloadFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;init-param&gt;&lt;description&gt;
 		              Allows developers to view the intermediade source code, when they pass
-		                a spillGroovy argument in the URL.					
-							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/base/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/user/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file
+		                a spillGroovy argument in the URL.
+							&lt;/description&gt;&lt;param-name&gt;showSource&lt;/param-name&gt;&lt;param-value&gt;1&lt;/param-value&gt;&lt;/init-param&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;*.dispatch&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch6/web-app/WEB-INF/web.xml</filename>
    </modified>
    <modified>
      <diff>@@ -124,4 +124,15 @@ td .errors {
 .prop .value {
 	text-align:left;
 	width:80%;
+}
+
+.prevLink, .step, .currentStep, .nextLink {
+	padding-right: 5px;
+}
+.currentStep {
+	font-weight:bold;
+}
+
+th.sorted a, th.sorted a:link, th.sorted a:visited, th.sorted a:hover, th.sortable a, th.sortable a:link, th.sortable a:visited, th.sortable a:hover {
+	color: white;
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch6/web-app/css/main.css</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 function warnBeforeRaceDelete() { 
      return confirm('Are you sure you want to delete this race?') 
-}
+} 
 
 function warnBeforeRegistrationDelete() { 
      return confirm('Are you sure you want to delete this registration?') 
-}
\ No newline at end of file
+} </diff>
      <filename>racetrack_ch6/web-app/js/racetrack.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,9 @@
 	&lt;classpathentry kind=&quot;src&quot; path=&quot;grails-tests&quot;/&gt;
 	&lt;classpathentry kind=&quot;con&quot; path=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot;/&gt;
 	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/ant/lib/ant.jar&quot;/&gt;
-    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
+    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-junit.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant.jar&quot; /&gt;
 
@@ -48,9 +50,9 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ejb3-persistence.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.2-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.5-SNAPSHOT.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.0.1-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.1-BETA-1.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-starter.jar&quot; /&gt;
 
@@ -80,13 +82,13 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/log4j-1.2.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ognl-2.7.jar&quot; /&gt;
-
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/org.mortbay.jetty.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/oro-2.0.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.5.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.6.0.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/serializer.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/servletapi-2.4.jar&quot; /&gt;
 
@@ -106,18 +108,20 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/standard-2.4.jar&quot; /&gt;
 
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xalan.jar&quot; /&gt;
+
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xerces-2.6.2.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xml-apis.jar&quot; /&gt;
 
 
-	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.4.2.jar&quot; /&gt;
+	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.5.jar&quot; /&gt;
 
 
 	&lt;classpathentry kind=&quot;output&quot; path=&quot;web-app/WEB-INF/classes&quot;/&gt;</diff>
      <filename>racetrack_ch7/.classpath</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-#Do not edit app.grails.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place!
-#Sun Mar 11 15:49:46 EDT 2007
-app.grails.version=0.4.2
+#Wed May 02 20:22:50 EDT 2007
+app.version=0.1
+app.grails.version=0.5
 app.name=racetrack</diff>
      <filename>racetrack_ch7/application.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,12 @@
-class ApplicationBootStrap { 
-    def init = { servletContext -&gt; 
+class ApplicationBootStrap {
+
+     def init = { servletContext -&gt;
         final String BACKUP_ADMIN = 'adminjoe' 
         if (!User.findByUserId(BACKUP_ADMIN)) { 
             new User(userId:BACKUP_ADMIN,password:'password').save() 
         } 
-    } 
- 
-    def destroy = { 
-    } 
-} 
+     }       
+     
+     def destroy = {
+     }
+} 
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/conf/ApplicationBootStrap.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class DevelopmentDataSource { 
+class DevelopmentDataSource {
    boolean pooling = true 
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_dev&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
    String password = &quot;&quot; 
-} 
+}</diff>
      <filename>racetrack_ch7/grails-app/conf/DevelopmentDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class TestDataSource { 
-   boolean pooling = true 
+class TestDataSource {
+   boolean pooling = true
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_test&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
-   String password = &quot;&quot; 
-} 
+   String password = &quot;&quot;
+}</diff>
      <filename>racetrack_ch7/grails-app/conf/TestDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch7/grails-app/conf/log4j.development.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch7/grails-app/conf/log4j.production.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch7/grails-app/conf/log4j.test.properties</filename>
    </modified>
    <modified>
      <diff>@@ -2,11 +2,13 @@ abstract class BaseController {
     def auth() { 
         if(!session.userId) { 
             def originalRequestParams = [controller:controllerName, action:actionName] 
+
             originalRequestParams.putAll(params) 
+
             session.originalRequestParams = originalRequestParams 
 
             redirect(controller:'user',action:'login') 
             return false 
         } 
-    } 
-}
\ No newline at end of file
+    }  
+} 
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/controllers/BaseController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
             
-class RaceController extends BaseController {
-    def beforeInterceptor = [action:this.&amp;auth, except:['search']] 
+class RaceController extends BaseController { 
+    def beforeInterceptor = [action:this.&amp;auth, except:['search']]
     
     def index = { redirect(action:list,params:params) }
 
@@ -48,8 +48,8 @@ class RaceController extends BaseController {
         def race = Race.get( params.id )
         if(race) {
              race.properties = params
-            if(race.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+            if(race.save()) {       
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:race.id)
             }
             else {
@@ -72,7 +72,7 @@ class RaceController extends BaseController {
         def race = new Race()
         race.properties = params
         if(race.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot; 
             redirect(action:show,id:race.id)
         }
         else {
@@ -80,42 +80,41 @@ class RaceController extends BaseController {
         }
     }
 
-    def search = { 
-        if (request.method == 'POST') { 
-            RaceQuery query = new RaceQuery() 
-            bindData(query, params) 
-
-            def criteria = Race.createCriteria() 
-
-            def results = criteria { 
-                and { 
-                    like('city', '%' + query.city + '%') 
-                    like('state', '%' + query.state + '%') 
-                    if (query.distance) { 
-                        switch (query.distanceOperator) { 
-                            case RaceQuery.DistanceOperator.AT_LEAST: 
-                                ge('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.EXACTLY: 
-                                eq('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.AT_MOST: 
-                                le('distance', query.distance) 
-                                break 
-                            default: 
-                                log.error &quot;Found unexpected value for distance&quot; 
-                                   + &quot; operator - ${query.distanceOperator}&quot; 
-                        } 
-                    } 
-                    // Add 1 day (24 hours) to the max date.  (If user selects a max 
-                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but 
-                    // the user will want any events occurring thru Jan 1st 23:59.) 
-                    between('startDateTime', query.minDate, query.maxDate + 1) 
-                } 
-            } 
-
-            render(view:'searchresults', model:[ raceList: results ])  
-        } 
-    } 
-
+    def search = {
+        if (request.method == 'POST') {
+            RaceQuery query = new RaceQuery()
+            bindData(query, params)
+    
+            def criteria = Race.createCriteria()
+    
+            def results = criteria {
+                and {
+                    like('city', '%' + query.city + '%')
+                    like('state', '%' + query.state + '%')
+                    if (query.distance) {
+                        switch (query.distanceOperator) {
+                            case RaceQuery.DistanceOperator.AT_LEAST:
+                                ge('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.EXACTLY:
+                                eq('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.AT_MOST:
+                                le('distance', query.distance)
+                                break
+                            default:
+                                log.error &quot;Found unexpected value for distance&quot;
+                                    + &quot; operator - ${query.distanceOperator}&quot;
+                        }
+                    }
+                    // Add 1 day (24 hours) to the max date.  If user selects a max
+                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but
+                    // the user will want any events occurring thru Jan 1st 23:59.
+                    between('startDateTime', query.minDate, query.maxDate + 1)
+                }
+            }
+    
+            render(view:'searchresults', model:[ raceList: results.adaptee ])
+        }
+    }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/controllers/RaceController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
             
-class RegistrationController extends BaseController {
-    def beforeInterceptor = [action:this.&amp;auth, except:'register'] 
+class RegistrationController extends BaseController { 
+    def beforeInterceptor = [action:this.&amp;auth, except:'register']
     
     def index = { redirect(action:list,params:params) }
 
@@ -49,7 +49,7 @@ class RegistrationController extends BaseController {
         if(registration) {
              registration.properties = params
             if(registration.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:registration.id)
             }
             else {
@@ -72,7 +72,7 @@ class RegistrationController extends BaseController {
         def registration = new Registration()
         registration.properties = params
         if(registration.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot;                 
             redirect(action:show,id:registration.id)
         }
         else {
@@ -80,6 +80,7 @@ class RegistrationController extends BaseController {
         }
     }
 
+
     def register = { 
         def registration = new Registration() 
         registration.properties = params 
@@ -90,8 +91,7 @@ class RegistrationController extends BaseController {
         } 
         else { 
             if(registration.save()) { 
-                flash.message =  
-                    &quot;Successfully registered for ${registration.race.name}&quot; 
+                flash.message = &quot;Successfully registered for ${registration.race.name}&quot; 
                 redirect(controller:'race',action:'search') 
             } 
             else { 
@@ -99,5 +99,5 @@ class RegistrationController extends BaseController {
                 return ['registration':registration,'race':race] 
             } 
         } 
-    } 
+    }  
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/controllers/RegistrationController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
             
 class UserController extends BaseController { 
     def beforeInterceptor = [action:this.&amp;auth, except:['login', 'logout']] 
-    
+
     def index = { redirect(action:list,params:params) }
 
     // the delete, save and update actions only</diff>
      <filename>racetrack_ch7/grails-app/controllers/UserController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Race {  
+class Race { 
     String name 
     Date startDateTime 
     String city 
@@ -7,16 +7,16 @@ class Race {
     Float cost 
     Integer maxRunners = 100000 
      
-    static hasMany = [registrations:Registration]  
+    static hasMany = [registrations:Registration]
     
     static constraints = { 
-        name(maxLength:50,blank:false) 
-        startDateTime(validator: {return (it &gt; new Date())})  
-        city(maxLength:30,blank:false) 
+        name(maxSize:50,blank:false) 
+        startDateTime(validator: {return (it &gt; new Date())}) 
+        city(maxSize:30,blank:false) 
         state(inList:['GA', 'NC', 'SC', 'VA'],blank:false) 
         distance(min:3.1f,max:100f) 
         cost(min:0f,max:999.99f) 
-    }
+    } 
     
-    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot;}     
-}
\ No newline at end of file
+    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot; }
+}	</diff>
      <filename>racetrack_ch7/grails-app/domain/Race.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Registration  {  
+class Registration { 
     Race race 
     String name 
     Date dateOfBirth 
@@ -6,19 +6,17 @@ class Registration  {
     String postalAddress 
     String emailAddress 
     Date createdAt = new Date() 
-    
+
     static belongsTo = Race 
-    
-    static optionals = [&quot;postalAddress&quot; ]  
-    
+
     static constraints = { 
-        name(maxLength:50,blank:false) 
+        name(maxSize:50,blank:false) 
         dateOfBirth(nullable:false) 
         gender(inList:[&quot;M&quot;, &quot;F&quot;]) 
-        postalAddress(maxLength:255) 
-        emailAddress(maxLength:50,email:true) 
+        postalAddress(nullable:true,maxSize:255) 
+        emailAddress(maxSize:50,email:true) 
         race(nullable:false) 
     } 
-
-  String toString() {&quot;${this.name} : ${this.emailAddress}&quot;}         
-}
\ No newline at end of file
+    
+    String toString(){&quot;${this.name}:${this.emailAddress}&quot;}         
+}	</diff>
      <filename>racetrack_ch7/grails-app/domain/Registration.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@ class User {
     String password 
  
     static constraints = { 
-        userId(length:6..8,unique:true) 
-        password(length:6..8) 
+        userId(size:6..8,unique:true) 
+        password(size:6..8) 
     } 
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/domain/User.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,29 +1,28 @@
 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.message=Property [{0}] of class [{1}] is not a valid [{2}].
+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.length.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
-default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
 default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
-default.invalid.max.length.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
-default.invalid.min.length.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{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.not.editable.message=Property [{0}] of class [{1}] with value [{2}] cannot be changed from [{3}] 
 
-race.name.blank=Please enter a name for this race 
+default.paginate.prev=Previous
+default.paginate.next=Next
+
+race.name.blank=Please enter a name for this race
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles 
 race.startDateTime.validator.invalid=Please enter a future date and time
 race.city.blank=Please enter a city for this race
-race.city.maxLength.exceeded=Please limit the city name to a maximum length of {3} characters
+race.city.maxSize.exceeded=Please limit the city name to a maximum length of {3} characters
 race.distance.nullable=Please enter a valid distance
 race.distance.min.notmet=Please enter a valid distance no fewer than {3} miles
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles
@@ -32,8 +31,8 @@ race.cost.min.notmet=Please enter a valid cost of at least ${3}
 race.cost.max.exceeded=Please enter a valid cost no more than ${3}
 
 registration.name.blank=Please enter a name
-registration.name.maxLength.exceeded=Please limit the name to a maximum length of {3} characters
-registration.postalAddress.maxLength.exceeded=Please limit the postal address to a maximum length of {3} characters
+registration.name.maxSize.exceeded=Please limit the name to a maximum length of {3} characters
+registration.postalAddress.maxSize.exceeded=Please limit the postal address to a maximum length of {3} characters
 registration.emailAddress.blank=Please enter an e-mail address
-registration.emailAddress.maxLength.exceeded=Please limit the e-mail address to a maximum length of {3} characters
+registration.emailAddress.maxSize.exceeded=Please limit the e-mail address to a maximum length of {3} characters
 registration.emailAddress.email.invalid=Please enter a valid e-mail address
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/i18n/messages.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,18 +1,22 @@
 &lt;g:if test=&quot;${!session.userId}&quot;&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;login&quot;&gt;Log in&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;login&quot;&gt;Log 
+in&lt;/g:link&gt; 
     &lt;/span&gt; 
 &lt;/g:if&gt; 
 &lt;g:else&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
         &lt;g:link controller=&quot;race&quot; action=&quot;list&quot;&gt; 
-            Manage Races &amp; Registrations 
+            Manage Races &amp;amp; Registrations 
         &lt;/g:link&gt; 
     &lt;/span&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;list&quot;&gt;Manage Administrators&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;list&quot;&gt;Manage Administrators 
+         &lt;/g:link&gt; 
     &lt;/span&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;logout&quot;&gt;Log out&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;logout&quot;&gt; 
+            Log out 
+        &lt;/g:link&gt; 
     &lt;/span&gt; 
 &lt;/g:else&gt; </diff>
      <filename>racetrack_ch7/grails-app/views/_adminmenubar.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -16,4 +16,4 @@
             &lt;/tr&gt; 
         &lt;/table&gt; 
     &lt;/body&gt; 
-&lt;/html&gt; 
+&lt;/html&gt; 
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/views/layouts/public.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -28,19 +28,19 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/race/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -31,19 +31,19 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='registrations'&gt;Registrations:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'registrations','errors')}'&gt;&lt;ul&gt;
     &lt;g:each var='r' in='${race?.registrations?}'&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/race/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New Race&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt; 
-                &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
+                    &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
             &lt;/span&gt; 
             &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
@@ -24,17 +24,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Start Date Time&lt;/th&gt;
-                                      
-                        &lt;th&gt;City&lt;/th&gt;
-                                      
-                        &lt;th&gt;State&lt;/th&gt;
-                                      
-                        &lt;th&gt;Distance&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;startDateTime&quot; title=&quot;Start Date Time&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;city&quot; title=&quot;City&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;state&quot; title=&quot;State&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;distance&quot; title=&quot;Distance&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/race/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,14 +1,15 @@
 &lt;html&gt; 
     &lt;head&gt; 
-        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt; 
+        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;  
+       charset=UTF-8&quot;/&gt; 
         &lt;meta name=&quot;layout&quot; content=&quot;public&quot; /&gt; 
         &lt;title&gt;Search for Races&lt;/title&gt; 
     &lt;/head&gt; 
     &lt;body&gt; 
-        &lt;div class=&quot;nav&quot;&gt; 
-            &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
-        &lt;/div&gt;
-        &lt;div class=&quot;body&quot;&gt; 
+      &lt;div class=&quot;nav&quot;&gt; 
+         &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
+      &lt;/div&gt; 
+      &lt;div class=&quot;body&quot;&gt; 
          &lt;h1&gt;Search for Races&lt;/h1&gt; 
          &lt;g:if test=&quot;${flash.message}&quot;&gt; 
              &lt;div class=&quot;message&quot;&gt;${flash.message}&lt;/div&gt; 
@@ -30,34 +31,37 @@
                        &lt;label for='state'&gt;State:&lt;/label&gt; 
                    &lt;/td&gt; 
                    &lt;td valign='top' class='value'&gt; 
-                       &lt;g:select name='state' from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
+                       &lt;g:select name='state'  
+                   from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
                       &lt;/g:select&gt; 
                    &lt;/td&gt; 
                &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='date'&gt;Date:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         between 
-                         &lt;g:datePicker name='minDate' precision='day' /&gt; 
-                         and 
-                         &lt;g:datePicker name='maxDate' precision='day' value='${new Date().plus(365*2)}'/&gt; 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         &lt;select name='distanceOperator' &gt; 
-                             &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
-                             &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
-                             &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
-                         &lt;/select&gt; 
-                         &lt;input type='text' name='distance' size='5'&gt;&lt;/input&gt; mi 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt;               
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='date'&gt;Date:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     between 
+                     &lt;g:datePicker name='minDate' precision='day' /&gt; 
+                     and 
+                     &lt;g:datePicker name='maxDate' precision='day'  
+                  value='${new Date().plus(365*2)}'/&gt; 
+                 &lt;/td&gt; 
+             &lt;/tr&gt; 
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     &lt;select name='distanceOperator' &gt; 
+                         &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
+                         &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
+                         &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
+                     &lt;/select&gt; 
+                     &lt;input type='text' name='distance' size='5'&gt; 
+             &lt;/input&gt; mi 
+                 &lt;/td&gt; 
+             &lt;/tr&gt;
             &lt;/table&gt; 
             &lt;/div&gt; 
             &lt;div class=&quot;buttons&quot;&gt; </diff>
      <filename>racetrack_ch7/grails-app/views/race/search.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -84,4 +84,4 @@
             &lt;/div&gt; 
         &lt;/div&gt; 
     &lt;/body&gt; 
-&lt;/html&gt;
\ No newline at end of file
+&lt;/html&gt; </diff>
      <filename>racetrack_ch7/grails-app/views/race/searchresults.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
   
 &lt;html&gt;
     &lt;head&gt;
-         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
+         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;  
          &lt;g:javascript library=&quot;racetrack&quot; /&gt;          
           &lt;meta name=&quot;layout&quot; content=&quot;main&quot; /&gt;
          &lt;title&gt;Show Race&lt;/title&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/race/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -25,10 +25,7 @@
                &lt;div class=&quot;dialog&quot;&gt;
                 &lt;table&gt;
                     &lt;tbody&gt;
-
-                       
-                       
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -36,12 +33,10 @@
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='createdAt'&gt;Created At:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'createdAt','errors')}'&gt;&lt;g:datePicker name='createdAt' value=&quot;${registration?.createdAt}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
-                       
                     &lt;/tbody&gt;
                &lt;/table&gt;
                &lt;/div&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/registration/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -31,7 +31,7 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -39,7 +39,7 @@
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -51,7 +51,7 @@
 
                &lt;div class=&quot;buttons&quot;&gt;
                      &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Update&quot; /&gt;&lt;/span&gt;
-                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/div&gt;
             &lt;/g:form&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/registration/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -21,17 +21,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Date Of Birth&lt;/th&gt;
-                                      
-                        &lt;th&gt;Gender&lt;/th&gt;
-                                      
-                        &lt;th&gt;Postal Address&lt;/th&gt;
-                                      
-                        &lt;th&gt;Email Address&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;dateOfBirth&quot; title=&quot;Date Of Birth&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;gender&quot; title=&quot;Gender&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;postalAddress&quot; title=&quot;Postal Address&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;emailAddress&quot; title=&quot;Email Address&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/registration/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -5,10 +5,10 @@
     &lt;title&gt;Register&lt;/title&gt; 
   &lt;/head&gt; 
   &lt;body&gt; 
+  &lt;div class=&quot;body&quot;&gt; 
       &lt;div class=&quot;nav&quot;&gt; 
           &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
       &lt;/div&gt;
-      &lt;div class=&quot;body&quot;&gt; 
       &lt;h1&gt;Register for ${race.name} &lt;/h1&gt; 
       &lt;em&gt;Start Date: 
         &lt;g:formatDate date=&quot;${race.startDateTime}&quot; format=&quot;EEE, MMM d, yyyy&quot;/&gt; 
@@ -89,4 +89,4 @@
       &lt;/g:form&gt; 
     &lt;/div&gt; 
   &lt;/body&gt; 
-&lt;/html&gt; 
\ No newline at end of file
+&lt;/html&gt; </diff>
      <filename>racetrack_ch7/grails-app/views/registration/register.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -78,7 +78,7 @@
                &lt;g:form controller=&quot;registration&quot;&gt;
                  &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;${registration?.id}&quot; /&gt;
                  &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Edit&quot; /&gt;&lt;/span&gt;
-                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/g:form&gt;
            &lt;/div&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/registration/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@
         &lt;div class=&quot;nav&quot;&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Create User&lt;/h1&gt;
@@ -27,9 +28,9 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/user/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+             &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Edit User&lt;/h1&gt;
@@ -33,9 +34,9 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                 &lt;/table&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/user/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@
         &lt;div class=&quot;nav&quot;&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;User List&lt;/h1&gt;
@@ -20,15 +21,14 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                   
-                                      
-                        &lt;th&gt;Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;User Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;Password&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+               
+                   	    &lt;g:sortableColumn property=&quot;id&quot; title=&quot;Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;userId&quot; title=&quot;User Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;password&quot; title=&quot;Password&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/user/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -44,4 +44,4 @@
             &lt;/g:form&gt; 
         &lt;/div&gt; 
     &lt;/body&gt; 
-&lt;/html&gt; 
+&lt;/html&gt; 
\ No newline at end of file</diff>
      <filename>racetrack_ch7/grails-app/views/user/login.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Show User&lt;/h1&gt;</diff>
      <filename>racetrack_ch7/grails-app/views/user/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ class RaceTests extends GroovyTestCase {
         def race = getValidRace() 
         race.name = 'It may very well take longer to type out the name of ' + 
             'this race than to just go run it.' 
-        assertValidationError(race, 'name', 'race.name.maxLength.exceeded') 
+        assertValidationError(race, 'name', 'race.name.maxSize.exceeded') 
     } 
      
     void testNameNullConstraint() {
@@ -48,7 +48,7 @@ class RaceTests extends GroovyTestCase {
     void testCityMaxConstraint() {
         def race = getValidRace()
         race.city = 'I pity the fool that lives in a city with a name this long.'
-        assertValidationError(race, 'city', 'race.city.maxLength.exceeded')
+        assertValidationError(race, 'city', 'race.city.maxSize.exceeded')
     }
 
     void testStateNullConstraint() {
@@ -84,7 +84,7 @@ class RaceTests extends GroovyTestCase {
     void testDistanceMaxConstraint() {
         def race = getValidRace()
         race.distance = 100.0001
-        assertValidationError(race, 'distance', 'race.distance.max.exceeded') // TODO Explain where to find the list of error codes - the validation reference page
+        assertValidationError(race, 'distance', 'race.distance.max.exceeded')
     }
 
     void testCostNullConstraint() {</diff>
      <filename>racetrack_ch7/grails-tests/RaceTests.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,10 @@ import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
-class ApplicationTagLib {
+class ApplicationTagLib { 
+	
+	def grailsUrlMappingsHolder
+	
     /**
      * Creates a link to a resource, generally used as a method rather than a tag.
      *
@@ -33,7 +36,7 @@ class ApplicationTagLib {
      */
     def createLinkTo = { attrs -&gt;
          out &lt;&lt; grailsAttributes.getApplicationUri(request)
-         if(attrs['dir']) {
+         if(attrs['dir'] || attrs['dir'] == '') {
             out &lt;&lt; &quot;/${attrs['dir']}&quot;
          }
          if(attrs['file']) {
@@ -50,7 +53,7 @@ class ApplicationTagLib {
     def link = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;a href=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // process remaining attributes
@@ -59,7 +62,7 @@ class ApplicationTagLib {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -79,29 +82,47 @@ class ApplicationTagLib {
         if(attrs['url']) {
              attrs = attrs.remove('url')
         }
-        // if the current attribute null set the controller uri to the current controller
-        if(attrs[&quot;controller&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;controller&quot;)
-        }
-        else {
-           out &lt;&lt; grailsAttributes.getControllerUri(request)
-        }
-        if(attrs[&quot;action&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;action&quot;)
-        }
-        if(attrs[&quot;id&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;id&quot;)
-        }
-        if(attrs['params']) {
-            def pms = attrs.remove('params')
-            out &lt;&lt; '?'
-            def i = 0
-            pms.each { k,v -&gt;
-                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
-                if(++i &lt; pms.size())
-                   out &lt;&lt; '&amp;'
-            }
-        }
+                                                     
+		def controller = attrs.containsKey(&quot;controller&quot;) ? attrs.remove(&quot;controller&quot;) : grailsAttributes.getController(request).controllerName
+		def action = attrs.remove(&quot;action&quot;)
+        def id = attrs.remove(&quot;id&quot;)
+        def params = attrs.params ? attrs.remove('params') : [:]
+
+        def url
+		try {
+            if(id) params.id = id
+            def mapping = grailsUrlMappingsHolder?.getReverseMapping(controller,action,params)
+			params.controller = controller
+			if(action) params.action = action  
+            url = mapping?.createURL(params)
+		}        
+		finally {
+			params.remove('controller')
+			params.remove('action')          
+			params.remove('id')
+		}
+		if(url) {
+			out &lt;&lt; url
+		}             
+		else {
+            out &lt;&lt; '/' &lt;&lt; controller
+	        if(action) {
+	            out &lt;&lt; '/' &lt;&lt; action
+	        }
+	        if(id) {
+	            out &lt;&lt; '/' &lt;&lt; id
+	        }
+	        if(params) {
+	            out &lt;&lt; '?'
+	            def i = 0
+	            params.each { k,v -&gt;
+	                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
+	                if(++i &lt; params.size())
+	                   out &lt;&lt; '&amp;'
+	            }
+	        }			
+		}
+															
     }
 
 	/**
@@ -127,8 +148,8 @@ class ApplicationTagLib {
 				} 				
 			}
 		}
-		out &lt;&lt; '&gt;'
-		body()
+		out &lt;&lt; '&gt;'  
+		out &lt;&lt; body()
 		out &lt;&lt; &quot;&lt;/${attrs.name}&gt;&quot;			
 	}	
 }</diff>
      <filename>racetrack_ch7/plugins/core/grails-app/taglib/ApplicationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -16,6 +16,7 @@ import org.springframework.validation.Errors;
 import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
+import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
 
  /**
  *  A  tag lib that provides tags for working with form controls
@@ -33,7 +34,10 @@ class FormTagLib {
 	def textField = { attrs -&gt;
 		attrs.type = &quot;text&quot;  
 		attrs.tagName = &quot;textField&quot; 
-		field(attrs)
+		def result = field(attrs)
+		if(result) {     
+			out &lt;&lt; result
+		}
 	}
 	/**
 	 * Creates a hidden field
@@ -41,7 +45,7 @@ class FormTagLib {
 	def hiddenField = { attrs -&gt;
 		attrs.type = &quot;hidden&quot;
 		attrs.tagName = &quot;hiddenField&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * Creates a submit button
@@ -49,7 +53,7 @@ class FormTagLib {
 	def submitButton = { attrs -&gt;
 		attrs.type = &quot;submit&quot;
 		attrs.tagName = &quot;submitButton&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * A general tag for creating fields
@@ -84,7 +88,7 @@ class FormTagLib {
     void resolveAttributes(attrs)
     {
         if(!attrs.name &amp;&amp; !attrs.field) {
-            throwTagError(&quot;Tag [$tagName] is missing required attribute [name] or [field]&quot;)
+            throwTagError(&quot;Tag [${attrs.tagName}] is missing required attribute [name] or [field]&quot;)
         }
         attrs.remove('tagName')
 
@@ -121,7 +125,7 @@ class FormTagLib {
     def form = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;form action=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // default to post
@@ -133,26 +137,34 @@ class FormTagLib {
 
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        def bodyContent = body()
+		out &lt;&lt; bodyContent
 
         // close tag
         out &lt;&lt; &quot;&lt;/form&gt;&quot;
     }
     /**
      * Creates a submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmit value=&quot;Edit&quot; /&gt;
+     *  &lt;g:actionSubmit action=&quot;Edit&quot; value=&quot;Some label for editing&quot; /&gt;
      *
      */
     def actionSubmit = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;submit&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+    	if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
-        // process remaining attributes
+
+		// add action and value
+		def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    	
+    	out &lt;&lt; &quot;&lt;input type=\&quot;submit\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+    	
+    	// process remaining attributes
         outputAttributes(attrs)
 
         // close tag
@@ -161,22 +173,30 @@ class FormTagLib {
     }
     /**
      * Creates a an image submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmitImage src=&quot;/images/submitButton.gif&quot; action=&quot;Edit&quot; /&gt;
      *
      */
     def actionSubmitImage = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;image&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+        if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
+        
+        // add action and value
+        def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    
+        out &lt;&lt; &quot;&lt;input type=\&quot;image\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+
+		// add image src        
         def src = attrs.remove('src')
         if(src) {
              out &lt;&lt; &quot;src=\&quot;${src}\&quot; &quot;
         }
+
         // process remaining attributes
         outputAttributes(attrs)
 
@@ -201,6 +221,8 @@ class FormTagLib {
 
         def value = (attrs['value'] ? attrs['value'] : xdefault)
         def name = attrs['name']
+        def id = attrs['id'] ? attrs['id'] : name
+
 		def noSelection = attrs['noSelection']
 		if (noSelection != null)
 		{
@@ -253,7 +275,7 @@ class FormTagLib {
 
         // create day select
         if (precision &gt;= PRECISION_RANKINGS[&quot;day&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_day\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_day\&quot; id=\&quot;${id}_day\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -272,7 +294,7 @@ class FormTagLib {
 
         // create month select
         if (precision &gt;= PRECISION_RANKINGS[&quot;month&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_month\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_month\&quot; id=\&quot;${id}_month\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -294,7 +316,7 @@ class FormTagLib {
 
         // create year select
         if (precision &gt;= PRECISION_RANKINGS[&quot;year&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_year\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_year\&quot; id=\&quot;${id}_year\&quot;&gt;&quot;
 
             if (noSelection) {
     			renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -313,7 +335,7 @@ class FormTagLib {
 
         // do hour select
         if (precision &gt;= PRECISION_RANKINGS[&quot;hour&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot; id=\&quot;${id}_hour\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -338,7 +360,7 @@ class FormTagLib {
 
         // do minute select
         if (precision &gt;= PRECISION_RANKINGS[&quot;minute&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot; id=\&quot;${id}_minute\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -360,7 +382,7 @@ class FormTagLib {
 	def renderNoSelectionOption = { noSelectionKey, noSelectionValue, value -&gt;
 		// If a label for the '--Please choose--' first item is supplied, write it out
         out &lt;&lt; '&lt;option value=&quot;' &lt;&lt; (noSelectionKey == null ? &quot;&quot; : noSelectionKey) &lt;&lt; '&quot;'
-        if(noSelectionKey == value) {
+        if(noSelectionKey.equals(value)) {
             out &lt;&lt; ' selected=&quot;selected&quot; '
         }
         out &lt;&lt; '&gt;' &lt;&lt; noSelectionValue.encodeAsHTML() &lt;&lt; '&lt;/option&gt;'
@@ -388,7 +410,7 @@ class FormTagLib {
         }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -405,7 +427,7 @@ class FormTagLib {
         attrs['optionValue'] = { &quot;${it.language}, ${it.country},  ${it.displayName}&quot; }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -425,7 +447,7 @@ class FormTagLib {
 		   	attrs.value = null
 		}
         // invoke generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -436,11 +458,15 @@ class FormTagLib {
      * &lt;g:select name=&quot;user.company.id&quot; from=&quot;${Company.list()}&quot; value=&quot;${user?.company.id}&quot; optionKey=&quot;id&quot; /&gt;
      */
     def select = { attrs -&gt;
+	    def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request)
+
         def from = attrs.remove('from')
         def keys = attrs.remove('keys')
         def optionKey = attrs.remove('optionKey')
         def optionValue = attrs.remove('optionValue')
         def value = attrs.remove('value')
+        def valueMessagePrefix = attrs.remove('valueMessagePrefix')
 		def noSelection = attrs.remove('noSelection')
         if (noSelection != null) {
             noSelection = noSelection.entrySet().iterator().next()
@@ -461,20 +487,21 @@ class FormTagLib {
         // create options from list
         if(from) {
             from.eachWithIndex { el,i -&gt;
+            	def keyValue = null
                 out &lt;&lt; '&lt;option '
                 if(keys) {
-                    out &lt;&lt; 'value=&quot;' &lt;&lt; keys[i] &lt;&lt; '&quot; '
-                    if(keys[i] == value) {
+                    keyValue = keys[i]
+                    out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
-               else if(optionKey) {
-                    def keyValue = null
+                else if(optionKey) {
                     if(optionKey instanceof Closure) {
                         keyValue = optionKey(el)
-                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                        out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
-                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getGrailsDomainClass(el.getClass().name)) {
+                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, el.getClass().name)) {
                         keyValue = el.ident()
                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
@@ -488,8 +515,9 @@ class FormTagLib {
                     }
                 }
                 else {
-                    out &lt;&lt; &quot;value=\&quot;${el}\&quot; &quot;
-                    if(el == value) {
+                	keyValue = el
+                    out &lt;&lt; &quot;value=\&quot;${keyValue}\&quot; &quot;
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
@@ -502,6 +530,19 @@ class FormTagLib {
                         out &lt;&lt; el.properties[optionValue].toString().encodeAsHTML()
                     }
                 }
+                else if(valueMessagePrefix) {
+                	def message = messageSource.getMessage(&quot;${valueMessagePrefix}.${keyValue}&quot;, null, null, locale)
+                	if(message) {
+                		out &lt;&lt; message.encodeAsHTML()
+                	}
+                	else if (keyValue) {
+                		out &lt;&lt; keyValue.encodeAsHTML()
+                	}
+					else {
+        	            def s = el.toString()
+    	                if(s) out &lt;&lt; s.encodeAsHTML()
+	                }
+                }
                 else {
                     def s = el.toString()
                     if(s) out &lt;&lt; s.encodeAsHTML()
@@ -554,6 +595,6 @@ class FormTagLib {
         outputAttributes(attrs)
 
         // close the tag, with no body
-        out &lt;&lt; ' &gt;&lt;/input&gt;'
+        out &lt;&lt; ' /&gt;'
      }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch7/plugins/core/grails-app/taglib/FormTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ class JavascriptTagLib  {
 		}
 		else {
 			out.println '&lt;script type=&quot;text/javascript&quot;&gt;'
-				body()
+				out &lt;&lt; body()
 			out.println '&lt;/script&gt;'
 		}
 	}
@@ -137,15 +137,15 @@ class JavascriptTagLib  {
     /**
      * A link to a remote uri that used the prototype library to invoke the link via ajax
      */
-    def remoteLink = { attrs, body -&gt;
+    def remoteLink = { attrs, body -&gt;  
        out &lt;&lt; &quot;&lt;a href=\&quot;&quot;    
 
        def cloned = deepClone(attrs)
-	   createLink(cloned)               
+	   out &lt;&lt; createLink(cloned)               
 
 	   out &lt;&lt; &quot;\&quot; onclick=\&quot;&quot;
         // create remote function
-        remoteFunction(attrs)   
+        out &lt;&lt; remoteFunction(attrs)   
 		attrs.remove('url')
         out &lt;&lt; &quot;return false;\&quot; &quot;
         // process remaining attributes
@@ -154,7 +154,7 @@ class JavascriptTagLib  {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -180,7 +180,7 @@ class JavascriptTagLib  {
 		else {
     		attrs.params = &quot;'${paramName}='+this.value&quot;			
 		}
-		remoteFunction(attrs)
+		out &lt;&lt; remoteFunction(attrs)
 		attrs.remove('params')
 		out &lt;&lt; &quot;\&quot;&quot;   
 		attrs.remove('url')
@@ -208,16 +208,16 @@ class JavascriptTagLib  {
 		// prepare form settings
 		prepareAjaxForm(p,attrs)
         
-        def params = [  onsubmit:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onsubmit:remoteFunction(attrs) + 'return false',
 					    method: (attrs.method? attrs.method : 'POST' ),
-					    action: (attrs.action? attrs.action : TagLibUtil.outToString(createLink,url))		                 
+					    action: (attrs.action? attrs.action : createLink(url))		                 
 		             ]
 		attrs.remove('url')		             
 	    params.putAll(attrs)
 		if(params.name &amp;&amp; !params.id)
 			params.id = params.name
-	    withTag(name:'form',attrs:params) {
-			body()   
+	    out &lt;&lt; withTag(name:'form',attrs:params) {
+			out &lt;&lt; body()   
 	    }		
     }
 
@@ -230,7 +230,7 @@ class JavascriptTagLib  {
 		// prepare form settings 
 		attrs.forSubmitTag = &quot;.form&quot;
 		prepareAjaxForm(p,attrs)    
-        def params = [  onclick:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onclick:remoteFunction(attrs) + 'return false',
 					    type: 'button',
 					    name: attrs.remove('name'),
 					    value: attrs.remove('value'), 
@@ -238,8 +238,8 @@ class JavascriptTagLib  {
 					    'class':attrs.remove('class')
 		             ]
 		             
-		withTag(name:'input', attrs:params) {
-			body()	
+		out &lt;&lt; withTag(name:'input', attrs:params) {
+			out &lt;&lt; body()	
 		}
     }
 	
@@ -275,7 +275,7 @@ class JavascriptTagLib  {
 			def sw = new StringWriter()
 			out = new PrintWriter(out)
 			// invoke body
-			body()
+			out &lt;&lt; body()
 			// restore out
 			out = tmp
 			js = sw.toString()
@@ -357,10 +357,10 @@ class PrototypeProvider implements JavascriptProvider {
 		
 		def pms = attrs.remove('params')   
 		if(attrs.url) {
-			taglib.createLink(attrs.url)			
+			out &lt;&lt; taglib.createLink(attrs.url)			
 		}                              
 		else {
-			taglib.createLink(attrs)			
+			out &lt;&lt; taglib.createLink(attrs)			
 		}
 
 		
@@ -415,6 +415,7 @@ class PrototypeProvider implements JavascriptProvider {
 	                    case 'true': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case 'false': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case ~/\s*function(\w*)\s*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
+	                    case ~/Insertion\..*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    default:ajaxOptions &lt;&lt; &quot;${k}:'${v}'&quot;; break;
 	                 }            	
             	}
@@ -441,10 +442,10 @@ class YahooProvider implements JavascriptProvider {
 		out &lt;&lt; &quot;YAHOO.util.Connect.asyncRequest('${method}','&quot;
 				
 		if(attrs.url) {
-			taglib.createLink(attrs.url)
+			out &lt;&lt; taglib.createLink(attrs.url)
 		}
 		else {
-			taglib.createLink(attrs)
+			out &lt;&lt; taglib.createLink(attrs)
 		}		
 		attrs.remove('url')
 		out &lt;&lt; &quot;',&quot;
@@ -504,7 +505,7 @@ class DojoProvider implements JavascriptProvider {
 		}		
 		 out &lt;&lt; 'dojo.io.bind({url:\''
 
-		 taglib.createLink(attrs) 
+		 out &lt;&lt; taglib.createLink(attrs) 
 		attrs.remove('params')
 		 out &lt;&lt; '\',load:function(type,data,evt) {'
 	    if(attrs.onLoaded) {</diff>
      <filename>racetrack_ch7/plugins/core/grails-app/taglib/JavascriptTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,6 +25,7 @@ import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
 class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants {
+	def out // to facilitate testing
 
     protected getPage() {
     	return request[PAGE]
@@ -91,7 +92,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 				}
 			}
 			if(invokeBody) {
-				body();	
+				out &lt;&lt; body()
 			}
 		}
 	}
@@ -134,54 +135,183 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         if(attrs.total == null)
             throwTagError(&quot;Tag [paginate] is missing required attribute [total]&quot;)
 		
-		def mkp = new groovy.xml.MarkupBuilder(out)
+		def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request) 
+		
 		def total = attrs.total.toInteger()
-		def max = params.max?.toInteger()
-		def offset = params.offset?.toInteger() 
 		def action = (attrs.action? attrs.action : 'list')
-		def breadcrumb = true
-		if(attrs.breadcrumb) breadcrumb = Boolean.valueOf(attrs.breadcrumb)
-			
+		def offset = params.offset?.toInteger()
+		def max = params.max?.toInteger()
+		def maxsteps = (attrs.maxsteps ? attrs.maxsteps.toInteger() : 10)
+
+        if(attrs.breadcrumb) {
+			log.warn(&quot;Tag [paginate] includes the [breadcrumb] attribute. This attribute is deprecated and will be removed in the future. Please update your code to use the [maxsteps] attribute instead.&quot;)
+		}
+
+		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)			
 		if(!max) max = (attrs.max ? attrs.max.toInteger() : 10)
-		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)
 		
-		def linkParams = [offset:offset-max,max:max]
-		def linkTagAttrs = ['class':'prevLink',action:action]
+		def linkParams = [offset:offset - max, max:max]
+		if(params.sort) linkParams.sort = params.sort
+		if(params.order) linkParams.order = params.order
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		def linkTagAttrs = [action:action]
 		if(attrs.controller) {
 			linkTagAttrs.controller = attrs.controller	
 		}
 		if(attrs.id) {
 			linkTagAttrs.id = attrs.id	
 		}
-		if(attrs.params)linkParams.putAll(attrs.params)
 		linkTagAttrs.params = linkParams
-	
-		def combined = max + offset
-		if(offset &gt; 0) {			
-			link(linkTagAttrs.clone(),{out&lt;&lt; (attrs.prev? attrs.prev : 'Previous' ) })
+		
+		// determine paging variables
+		def steps = maxsteps &gt; 0
+		int currentstep = (offset / max) + 1
+		int firststep = 1
+		int laststep = Math.round(Math.ceil(total / max))
+			
+		// display previous link when not on firststep
+		if(currentstep &gt; firststep) {
+			linkTagAttrs.class = 'prevLink'
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.prev ? attrs.prev : messageSource.getMessage('default.paginate.prev', null, 'Previous', locale))
+			 }
 		}
 		
-		if(total &gt; max) {
-			linkTagAttrs.'class' = 'step'
-			if(breadcrumb) {
-				def j = 0
-				0.step(total,max) { i -&gt;
-					if(offset == i) {
-						mkp.a('class':'step',&quot;${++j}&quot;)	
-					}
-					else {
-						linkParams.offset=i
-						link(linkTagAttrs.clone(),{out&lt;&lt;++j})	
-					}
-				}			
+		// display steps when steps are enabled and laststep is not firststep
+		if(steps &amp;&amp; laststep &gt; firststep) {
+			linkTagAttrs.class = 'step'
+
+			// determine begin and endstep paging variables
+			int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
+			int endstep = currentstep + Math.round(maxsteps / 2) - 1
+			
+			if(beginstep &lt; firststep) {
+				beginstep = firststep
+				endstep = maxsteps
+			}
+			if(endstep &gt; laststep) {
+				beginstep = laststep - maxsteps + 1
+				if(beginstep &lt; firststep) {
+					beginstep = firststep
+				}
+				endstep = laststep
+			}
+
+			// display firststep link when beginstep is not firststep
+			if(beginstep &gt; firststep) {
+				linkParams.offset = 0
+				out &lt;&lt; link(linkTagAttrs.clone()) {firststep.toString()}
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+			}
+
+			// display paginate steps
+			(beginstep..endstep).each { i -&gt;
+				if(currentstep == i) {
+					out &lt;&lt; &quot;&lt;span class=\&quot;currentStep\&quot;&gt;${i}&lt;/span&gt;&quot;
+				}
+				else {
+					linkParams.offset = (i - 1) * max
+					out &lt;&lt; link(linkTagAttrs.clone()) {i.toString()}
+				}
+			}	
+			
+			// display laststep link when endstep is not laststep
+			if(endstep &lt; laststep) {
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+				linkParams.offset = (laststep -1) * max
+				out &lt;&lt; link(linkTagAttrs.clone()) { laststep.toString() }
+			}		
+		}
+		
+		// display next link when not on laststep
+		if(currentstep &lt; laststep) {	
+			linkTagAttrs.class = 'nextLink'			
+			linkParams.offset = offset + max
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.next ? attrs.next : messageSource.getMessage('default.paginate.next', null, 'Next', locale))
 			}			
 		}
-		linkParams.offset = offset+max
-		if(combined &lt; total) {	
-			linkTagAttrs.'class'='nextLink'			
-			link(linkTagAttrs,{out&lt;&lt; (attrs.'next'? attrs.'next' : 'Next' )})			
+
+	}
+
+	/**
+	 * Renders a sortable column to support sorting in list views
+	 *
+	 * Attributes:
+	 *
+	 * property - name of the property relating to the field
+	 * defaultOrder (optional) - default order for the property; choose between asc (default if not provided) and desc
+	 * title (optional*) - title caption for the column
+	 * titleKey (optional*) - title key to use for the column, resolved against the message source
+	 * params (optional) - a map containing request parameters
+	 *
+	 * Attribute title or titleKey is required. When both attributes are specified then titleKey takes precedence,
+	 * resulting in the title caption to be resolved against the message source. In case when the message could
+	 * not be resolved, the title will be used as title caption. 
+	 *
+	 * Examples:
+	 *
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; style=&quot;width: 200px&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; titleKey=&quot;book.title&quot; /&gt;	 
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; titleKey=&quot;book.releaseDate&quot; /&gt;
+	 */
+	def sortableColumn = { attrs -&gt;
+
+		if(!attrs.property)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [property]&quot;) 
+		
+		if(!attrs.title &amp;&amp; !attrs.titleKey)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [title] or [titleKey]&quot;)
+
+		def property = attrs.remove(&quot;property&quot;)
+		def action = attrs.action ? attrs.remove(&quot;action&quot;) : &quot;list&quot;
+		
+		def defaultOrder = attrs.remove(&quot;defaultOrder&quot;)
+		if(defaultOrder != &quot;desc&quot;) defaultOrder = &quot;asc&quot;
+
+		// current sorting property and order
+		def sort = params.sort
+		def order = params.order
+
+		// add sorting property and params to link params
+		def linkParams = [sort:property]
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		// determine and add sorting order for this column to link params
+		attrs.class = &quot;sortable&quot;
+		if(property == sort) {
+			attrs.class = attrs.class + &quot; sorted &quot; + order
+			if(order == &quot;asc&quot;) {
+				linkParams.order = &quot;desc&quot;
+			}
+			else {
+				linkParams.order = &quot;asc&quot;
+			}
+		}
+		else {
+			linkParams.order = defaultOrder
+		}
+
+		// determine column title
+		def title = attrs.remove(&quot;title&quot;)
+		def titleKey = attrs.remove(&quot;titleKey&quot;)
+		if(titleKey) {
+			if(!title) title = titleKey
+			def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+			def locale = RCU.getLocale(request)
+			title = messageSource.getMessage(titleKey, null, title, locale)
 		}
 
+		out &lt;&lt; &quot;&lt;th &quot;
+		// process remaining attributes
+		attrs.each { k, v -&gt;
+			out &lt;&lt; &quot;${k}=\&quot;${v.encodeAsHTML()}\&quot; &quot;
+		}
+		out &lt;&lt; &quot;&gt;${link(action:action, params:linkParams) { title }}&lt;/th&gt;&quot;
 	}
 
     /**
@@ -199,14 +329,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         def uri = grailsAttributes.getTemplateUri(attrs.template,request)
         def var = attrs['var']
 
-        def url = servletContext.getResource(uri)
-        if(!url)
-            throwTagError(&quot;No template found for name [${attrs.template}] in tag [render]&quot;)
-
-        def t = engine.createTemplate(  uri,
-                                        servletContext,
-                                        request,
-                                        response)
+        def t = engine.createTemplate( uri )
 
         if(attrs.model instanceof Map) {
             t.make( attrs.model ).writeTo(out)
@@ -246,14 +369,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 	        def engine = grailsAttributes.getPagesTemplateEngine()
 	        def uri = grailsAttributes.getTemplateUri(attrs.template,request)
 
-	        def url = servletContext.getResource(uri)
-	        if(!url)
-	            throwTagError(&quot;No template found for name [${attrs.template}] in tag [include]&quot;)
-
-	        def t = engine.createTemplate(  uri,
-	                                        servletContext,
-	                                        request,
-	                                        response)
+	        def t = engine.createTemplate(  uri )
 			
 			t.make().writeTo(out)
 		}</diff>
      <filename>racetrack_ch7/plugins/core/grails-app/taglib/RenderTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -152,7 +152,7 @@ class UITagLib {
 	 * &lt;g:richTextEditor name=&quot;editor&quot; height=&quot;400&quot; /&gt;
 	 */
 	def richTextEditor = { attrs -&gt;
-		withTag(name:'script',attributes:[type:'text/javascript']) {
+		out &lt;&lt; withTag(name:'script',attributes:[type:'text/javascript']) {
 			if(attrs.onComplete) {
 				out.println &quot;function FCKeditor_OnComplete( editorInstance ) {&quot;
 					out.println &quot;${attrs.onComplete}(editorInstance);&quot;					
@@ -162,24 +162,53 @@ class UITagLib {
 			var oFCKeditor = new FCKeditor( '${attrs.name}' ) ;
 			oFCKeditor.BasePath	 = \&quot;&quot;&quot;&quot;
 			if(attrs.basepath) {
-				createLinkTo(dir:attrs.basepath)
+				out &lt;&lt; createLinkTo(dir:attrs.basepath)
 			}
 			else {
-				createLinkTo(dir:&quot;fckeditor/&quot;)
+			    out &lt;&lt; createLinkTo(dir:&quot;fckeditor/&quot;)
 			}
 			out.println '&quot;;'
 			if(attrs.toolbar) {
 				out &lt;&lt; &quot;oFCKeditor.ToolbarSet	 = '${attrs.toolbar}';&quot; 	
-			}			
+			}
+			// add width support
+			if(attrs.width)			
+				out.println &quot;oFCKeditor.Width	= '${attrs.width}';&quot;
+			
 			if(attrs.height)			
-				out.println &quot;oFCKeditor.Height	= ${attrs.height};&quot;
+				out.println &quot;oFCKeditor.Height	= '${attrs.height}';&quot;
+			
+			// add skin support, values to choose: &quot;default&quot;, &quot;office2003&quot;, &quot;silver&quot;
+			if(attrs.skin)
+				out.println &quot;oFCKeditor.Config['SkinPath'] = 'skins/${attrs.skin}/';&quot;
+			
+			// check the browser compatibility when rendering the editor.  default value: true, values to choose: true, false, 
+			if(attrs.checkBrowser)
+				out.println &quot;oFCKeditor.CheckBrowser = ${attrs.checkBrowser};&quot;
+
+			// show error messages on errors while rendering the editor.   default value: true, values to choose: true, false
+			if(attrs.displayErrors)
+				out.println &quot;oFCKeditor.DisplayErrors = ${attrs.displayErrors};&quot;
+
+			// oFCKeditor.Config      AutoDetectLanguage:true/false, DefaultLanguage:'pt-BR' and so on
+			if(attrs.config) {
+				if (attrs.config instanceof Map) {
+					attrs.config.each { k, v -&gt;
+						out.println &quot;oFCKeditor.Config['$k'] = '$v';&quot;
+					}
+				} else {
+					throw new Exception(&quot;&quot;&quot;The format of config is not correct, it should be like &quot;[AutoDetectLanguage:false, DefaultLanguage:'pt-BR']&quot;   &quot;&quot;&quot;)
+				}
+			}
+
 			if(attrs.value) {
 				out &lt;&lt; &quot;oFCKeditor.Value	= \&quot;&quot;
-				escapeJavascript(Collections.EMPTY_MAP,attrs.value)
+			    out &lt;&lt; escapeJavascript(Collections.EMPTY_MAP,attrs.value)
 				out.println &quot;\&quot; ;&quot;
 			}
 			
-			out.println &quot;oFCKeditor.Create();&quot;			
+			out.println &quot;oFCKeditor.Create();&quot;	
+
 		}
 	}
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch7/plugins/core/grails-app/taglib/UITagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -32,9 +32,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def checkList = []
         if(model) {
-            checkList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors))
-            }
+            checkList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             checkList &lt;&lt; attrs['bean']
@@ -45,7 +43,7 @@ class ValidationTagLib {
 					if(ra) {
                         if(ra instanceof Errors)
                             checkList &lt;&lt; ra
-	                    else if ((ra.properties.errors) &amp;&amp; (ra.errors instanceof Errors)) {
+	                    else if (ra.properties?.errors instanceof Errors) {
                             checkList &lt;&lt; ra
 						}
 					}
@@ -55,23 +53,29 @@ class ValidationTagLib {
 
         for(i in checkList) {
             def errors = null
-            if(i instanceof Errors) {
+            if (i instanceof Errors) {
                errors = i
             }
-            else {
-				if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
-	                if (i.hasErrors())
-	                    errors = i.errors
-	            }
+            else {       
+				try {
+					if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
+		                if (i.hasErrors())
+		                    errors = i.errors
+		            }
+					
+				}   
+				catch(MissingPropertyException mpe) {
+					// ignore
+				}
 			}
             if(errors) {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
-                        body()
+                        out &lt;&lt; body()
                     }
                 }
                 else {
-                    body()
+                    out &lt;&lt; body()
                 }
             }
         }
@@ -84,9 +88,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def errorList = []
         if(model) {
-            errorList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors)) 
-            }
+            errorList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             errorList &lt;&lt; attrs['bean']
@@ -95,9 +97,9 @@ class ValidationTagLib {
             request.attributeNames.each {
                 def ra = request[it]
                 if(ra) {
-                    if(ra instanceof Errors)
+                    if (ra instanceof Errors)
                         errorList &lt;&lt; ra
-                    else if ((ra.errors != null) &amp;&amp; (ra.errors instanceof Errors)) {
+                    else if (ra.properties?.errors instanceof Errors) {
                         errorList &lt;&lt; ra
 					}
                 }
@@ -119,13 +121,13 @@ class ValidationTagLib {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
                         errors.getFieldErrors( attrs[&quot;field&quot;] ).each {
-                            body(it)
+                            out &lt;&lt; body(it)
                         }
                     }
                 }
                 else {
                     errors.allErrors.each {
-                        body( it )
+                        out &lt;&lt; body( it )
                     }
                 }
             }
@@ -141,9 +143,9 @@ class ValidationTagLib {
 
         if(renderAs == 'list') {
             out &lt;&lt; &quot;&lt;ul&gt;&quot;
-            eachError(attrs, {
+            out &lt;&lt; eachError(attrs, {
                 out &lt;&lt; &quot;&lt;li&gt;&quot;
-                message(error:it)
+                out &lt;&lt; message(error:it)
                 out &lt;&lt; &quot;&lt;/li&gt;&quot;
               }
             )
@@ -219,7 +221,7 @@ class ValidationTagLib {
         }
 
         def app = grailsAttributes.getGrailsApplication()
-        def dc = app.getGrailsDomainClass(againstClass)
+        def dc = app.getDomainClass(againstClass)
 
         if(!dc)
             throwTagError(&quot;Tag [validate] could not find a domain class to validate against for name [${againstClass}]&quot;)</diff>
      <filename>racetrack_ch7/plugins/core/grails-app/taglib/ValidationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ class URLCodec {
     }
 
     static decode = { obj -&gt;
-        URLEncoder.decode(obj.toString(), URLCodec.getEncoding())
+        URLDecoder.decode(obj.toString(), URLCodec.getEncoding())
     }
 
 	private static def getEncoding() {</diff>
      <filename>racetrack_ch7/plugins/core/grails-app/utils/URLCodec.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch7/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,9 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 
-&lt;beans&gt;
 	&lt;bean id=&quot;grailsApplication&quot; class=&quot;org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean&quot;&gt;
 		&lt;description&gt;Grails application factory bean&lt;/description&gt;
 		&lt;property name=&quot;groovyFiles&quot;&gt;
@@ -25,7 +27,7 @@
         &lt;property name=&quot;pluginManager&quot; ref=&quot;pluginManager&quot; /&gt;
     &lt;/bean&gt;
 	
-    &lt;bean id=&quot;grailsResourceHolder&quot; singleton=&quot;false&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
+    &lt;bean id=&quot;grailsResourceHolder&quot; scope=&quot;prototype&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
         &lt;property name=&quot;resources&quot;&gt;
               &lt;value&gt;classpath*:**/grails-app/**/*.groovy&lt;/value&gt;
         &lt;/property&gt;</diff>
      <filename>racetrack_ch7/web-app/WEB-INF/applicationContext.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch7/web-app/WEB-INF/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,254 @@
     &lt;uri&gt;http://grails.codehaus.org/tags&lt;/uri&gt;
 
     &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var}
+        &lt;/description&gt;
+        &lt;name&gt;set&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovySetTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var} into the page context
+        &lt;/description&gt;
+        &lt;name&gt;def&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyDefTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical if tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;if&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical else tag as fallback if the if condition fails
+        &lt;/description&gt;
+        &lt;name&gt;else&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical elseif tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;elseif&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;
+        	Tag to loop over a collection while the test expression returns true
+        &lt;/description&gt;
+        &lt;name&gt;while&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyWhileTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;each&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyEachTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;findAll&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyFindAllTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to filter the elements to iterate over&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and collects the elements
+        	you want to work with&lt;/description&gt;
+        &lt;name&gt;collect&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyCollectTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to use to collect the elements. The
+        	expression must retur true to add the element to the
+        	collection&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and filters the elements
+        with a regular expression&lt;/description&gt;
+        &lt;name&gt;grep&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyGrepTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The regular expression to filter the element with. The
+        	filter is a simple Groovy Regex&lt;/description&gt;
+            &lt;name&gt;filter&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;A tag that attempts to render an input for a bean property
+        into an appropriate component based on the type. It uses the templates
+        defined in &quot;grails-app/views/scaffolding&quot; to achieve this by looking up
+		the template by type.&lt;/description&gt;
+        &lt;name&gt;renderInput&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyRenderInputTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The Bean to render the input for&lt;/description&gt;
+            &lt;name&gt;bean&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The property of the bean to render input for&lt;/description&gt;
+            &lt;name&gt;property&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
         &lt;name&gt;link&lt;/name&gt;
         &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag&lt;/tag-class&gt;
         &lt;body-content&gt;JSP&lt;/body-content&gt;</diff>
      <filename>racetrack_ch7/web-app/WEB-INF/tld/grails.tld</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
 &lt;web-app version=&quot;2.4&quot;
          xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
          xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</diff>
      <filename>racetrack_ch7/web-app/WEB-INF/web.template.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1 +1 @@
-&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/base/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/user/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file
+&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;*.dispatch&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch7/web-app/WEB-INF/web.xml</filename>
    </modified>
    <modified>
      <diff>@@ -124,4 +124,15 @@ td .errors {
 .prop .value {
 	text-align:left;
 	width:80%;
+}
+
+.prevLink, .step, .currentStep, .nextLink {
+	padding-right: 5px;
+}
+.currentStep {
+	font-weight:bold;
+}
+
+th.sorted a, th.sorted a:link, th.sorted a:visited, th.sorted a:hover, th.sortable a, th.sortable a:link, th.sortable a:visited, th.sortable a:hover {
+	color: white;
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch7/web-app/css/main.css</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 function warnBeforeRaceDelete() { 
      return confirm('Are you sure you want to delete this race?') 
-}
+} 
 
 function warnBeforeRegistrationDelete() { 
      return confirm('Are you sure you want to delete this registration?') 
-}
\ No newline at end of file
+} </diff>
      <filename>racetrack_ch7/web-app/js/racetrack.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,9 @@
 	&lt;classpathentry kind=&quot;src&quot; path=&quot;grails-tests&quot;/&gt;
 	&lt;classpathentry kind=&quot;con&quot; path=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot;/&gt;
 	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/ant/lib/ant.jar&quot;/&gt;
-    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
+    &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-junit.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant-nodeps.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ant.jar&quot; /&gt;
 
@@ -48,9 +50,9 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ejb3-persistence.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.2-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/gant-0.2.5-SNAPSHOT.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.0.1-SNAPSHOT.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-all-1.1-BETA-1.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/groovy-starter.jar&quot; /&gt;
 
@@ -80,13 +82,13 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/log4j-1.2.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/ognl-2.7.jar&quot; /&gt;
-
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/org.mortbay.jetty.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/oro-2.0.8.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.5.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/quartz-1.6.0.jar&quot; /&gt;
+
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/serializer.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/servletapi-2.4.jar&quot; /&gt;
 
@@ -106,18 +108,20 @@
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/standard-2.4.jar&quot; /&gt;
 
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xalan.jar&quot; /&gt;
+
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xerces-2.6.2.jar&quot; /&gt;
 
 &lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/lib/xml-apis.jar&quot; /&gt;
 
 
-	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.4.2.jar&quot; /&gt;
+	&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-core-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-crud-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-gorm-0.5.jar&quot; /&gt;
 
-&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.4.2.jar&quot; /&gt;
+&lt;classpathentry kind=&quot;var&quot; path=&quot;GRAILS_HOME/dist/grails-web-0.5.jar&quot; /&gt;
 
 
 	&lt;classpathentry kind=&quot;output&quot; path=&quot;web-app/WEB-INF/classes&quot;/&gt;</diff>
      <filename>racetrack_ch8/.classpath</filename>
    </modified>
    <modified>
      <diff>@@ -1,2 +1,2 @@
-2007-03-11 21:30:49,103 WARN  [UserController] Shields up!  Somebody's trying to hack through our rock-solid DEFCON 1 security -- User ID - admin, Password - 
+2007-05-19 16:47:28,583 WARN  [grails.app.controller.UserController] Shields up!  Somebody's trying to hack through our rock-solid DEFCON 1 security -- User ID - adminjoe, Password - letmein
  
\ No newline at end of file</diff>
      <filename>racetrack_ch8/access.log</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-#Do not edit app.grails.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place!
-#Sun Mar 11 15:49:46 EDT 2007
-app.grails.version=0.4.2
+#Wed May 02 20:22:50 EDT 2007
+app.version=0.1
+app.grails.version=0.5
 app.name=racetrack</diff>
      <filename>racetrack_ch8/application.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,12 @@
-class ApplicationBootStrap { 
-    def init = { servletContext -&gt; 
+class ApplicationBootStrap {
+
+     def init = { servletContext -&gt;
         final String BACKUP_ADMIN = 'adminjoe' 
         if (!User.findByUserId(BACKUP_ADMIN)) { 
             new User(userId:BACKUP_ADMIN,password:'password').save() 
         } 
-    } 
- 
-    def destroy = { 
-    } 
-} 
+     }       
+     
+     def destroy = {
+     }
+} 
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/conf/ApplicationBootStrap.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class DevelopmentDataSource { 
+class DevelopmentDataSource {
    boolean pooling = true 
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_dev&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
    String password = &quot;&quot; 
-} 
+}</diff>
      <filename>racetrack_ch8/grails-app/conf/DevelopmentDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -4,5 +4,5 @@ class ProductionDataSource {
    String url = &quot;jdbc:mysql://localhost/racetrack_prod&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;prod&quot; 
-   String password = &quot;wahoowa&quot;
-}
+   String password = &quot;wahoowa&quot; 
+}
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/conf/ProductionDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,8 @@
-class TestDataSource { 
-   boolean pooling = true 
+class TestDataSource {
+   boolean pooling = true
    String dbCreate = &quot;update&quot; 
    String url = &quot;jdbc:mysql://localhost/racetrack_test&quot; 
    String driverClassName = &quot;com.mysql.jdbc.Driver&quot; 
    String username = &quot;jason&quot; 
-   String password = &quot;&quot; 
-} 
+   String password = &quot;&quot;
+}</diff>
      <filename>racetrack_ch8/grails-app/conf/TestDataSource.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch8/grails-app/conf/log4j.development.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -38,15 +59,10 @@ log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
 
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        
-
 log4j.appender.access=org.apache.log4j.FileAppender 
 log4j.appender.access.file=access.log 
 log4j.appender.access.layout=org.apache.log4j.PatternLayout 
 log4j.appender.access.layout.ConversionPattern=%d %p %x [%c] %m%n 
  
-log4j.logger.UserController=warn,access 
-log4j.additivity.UserController=false 
-
+log4j.logger.grails.app.controller.UserController=warn,access 
+log4j.additivity.grails.app.controller.UserController=false
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/conf/log4j.production.properties</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,28 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.rootLogger=error, stdout
 
 
-# Enable this logger to log Hibernate output
+# This logger is for your own application artefact logs
+# Artefacts are logged by their type and optionally class name i.e:
+#
+# log4j.logger.grails.app.controller.HelloController=debug, stdout
+# ...will control the logs from just that controller
+#
+# log4j.logger.grails.app.domain=trace, stdout
+# ...will control the logs for all domain classes
+#
+# At the time of writing, supported artefact type ids include:
+# domain (aka Domain Class), task (aka Job), service, dataSource,
+# controller, tagLib, urlMappings, codec, bootstrap
+#
+# The default &quot;info&quot; level for all artefacts is set here
+log4j.logger.grails.app=info,stdout
+log4j.additivity.grails.app=false
+
+## This logger is for Grails' public APIs within the grails. package
+log4j.logger.grails=info,stdout
+log4j.additivity.grails=false
+
+## Enable this logger to log Hibernate output
 # handy to see its database interaction activity
 #log4j.logger.org.hibernate=debug,stdout
 #log4j.additivity.org.hibernate=false
@@ -37,7 +58,3 @@ log4j.logger.org.codehaus.groovy.grails.plugins=info,stdout
 log4j.additivity.org.codehaus.groovy.grails.plugins=false
 log4j.logger.grails.spring=info,stdout 
 log4j.additivity.grails.spring=false  
-
-# This logger is for Grails' public APIs within the grails. package
-log4j.logger.grails=info,stdout
-log4j.additivity.grails=false        </diff>
      <filename>racetrack_ch8/grails-app/conf/log4j.test.properties</filename>
    </modified>
    <modified>
      <diff>@@ -2,11 +2,13 @@ abstract class BaseController {
     def auth() { 
         if(!session.userId) { 
             def originalRequestParams = [controller:controllerName, action:actionName] 
+
             originalRequestParams.putAll(params) 
+
             session.originalRequestParams = originalRequestParams 
 
             redirect(controller:'user',action:'login') 
             return false 
         } 
-    } 
-}
\ No newline at end of file
+    }  
+} 
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/controllers/BaseController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
             
-class RaceController extends BaseController {
-    def beforeInterceptor = [action:this.&amp;auth, except:['search']] 
+class RaceController extends BaseController { 
+    def beforeInterceptor = [action:this.&amp;auth, except:['search']]
     
     def index = { redirect(action:list,params:params) }
 
@@ -48,8 +48,8 @@ class RaceController extends BaseController {
         def race = Race.get( params.id )
         if(race) {
              race.properties = params
-            if(race.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+            if(race.save()) {       
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:race.id)
             }
             else {
@@ -72,7 +72,7 @@ class RaceController extends BaseController {
         def race = new Race()
         race.properties = params
         if(race.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot; 
             redirect(action:show,id:race.id)
         }
         else {
@@ -80,42 +80,41 @@ class RaceController extends BaseController {
         }
     }
 
-    def search = { 
-        if (request.method == 'POST') { 
-            RaceQuery query = new RaceQuery() 
-            bindData(query, params) 
-
-            def criteria = Race.createCriteria() 
-
-            def results = criteria { 
-                and { 
-                    like('city', '%' + query.city + '%') 
-                    like('state', '%' + query.state + '%') 
-                    if (query.distance) { 
-                        switch (query.distanceOperator) { 
-                            case RaceQuery.DistanceOperator.AT_LEAST: 
-                                ge('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.EXACTLY: 
-                                eq('distance', query.distance) 
-                                break 
-                            case RaceQuery.DistanceOperator.AT_MOST: 
-                                le('distance', query.distance) 
-                                break 
-                            default: 
-                                log.error &quot;Found unexpected value for distance&quot; 
-                                   + &quot; operator - ${query.distanceOperator}&quot; 
-                        } 
-                    } 
-                    // Add 1 day (24 hours) to the max date.  (If user selects a max 
-                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but 
-                    // the user will want any events occurring thru Jan 1st 23:59.) 
-                    between('startDateTime', query.minDate, query.maxDate + 1) 
-                } 
-            } 
-
-            render(view:'searchresults', model:[ raceList: results ])  
-        } 
-    } 
-
+    def search = {
+        if (request.method == 'POST') {
+            RaceQuery query = new RaceQuery()
+            bindData(query, params)
+    
+            def criteria = Race.createCriteria()
+    
+            def results = criteria {
+                and {
+                    like('city', '%' + query.city + '%')
+                    like('state', '%' + query.state + '%')
+                    if (query.distance) {
+                        switch (query.distanceOperator) {
+                            case RaceQuery.DistanceOperator.AT_LEAST:
+                                ge('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.EXACTLY:
+                                eq('distance', query.distance)
+                                break
+                            case RaceQuery.DistanceOperator.AT_MOST:
+                                le('distance', query.distance)
+                                break
+                            default:
+                                log.error &quot;Found unexpected value for distance&quot;
+                                    + &quot; operator - ${query.distanceOperator}&quot;
+                        }
+                    }
+                    // Add 1 day (24 hours) to the max date.  If user selects a max
+                    // date of Jan 1st, the date object will hold Jan 1st 00:00, but
+                    // the user will want any events occurring thru Jan 1st 23:59.
+                    between('startDateTime', query.minDate, query.maxDate + 1)
+                }
+            }
+    
+            render(view:'searchresults', model:[ raceList: results.adaptee ])
+        }
+    }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/controllers/RaceController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
             
-class RegistrationController extends BaseController {
-    def beforeInterceptor = [action:this.&amp;auth, except:'register'] 
+class RegistrationController extends BaseController { 
+    def beforeInterceptor = [action:this.&amp;auth, except:'register']
     
     def index = { redirect(action:list,params:params) }
 
@@ -49,7 +49,7 @@ class RegistrationController extends BaseController {
         if(registration) {
              registration.properties = params
             if(registration.save()) {
-                flash.message = &quot;${params.name} updated.&quot;
+                flash.message = &quot;${params.name} updated.&quot;                 
                 redirect(action:show,id:registration.id)
             }
             else {
@@ -72,7 +72,7 @@ class RegistrationController extends BaseController {
         def registration = new Registration()
         registration.properties = params
         if(registration.save()) {
-            flash.message = &quot;${params.name} saved.&quot;
+            flash.message = &quot;${params.name} saved.&quot;                 
             redirect(action:show,id:registration.id)
         }
         else {
@@ -80,6 +80,7 @@ class RegistrationController extends BaseController {
         }
     }
 
+
     def register = { 
         def registration = new Registration() 
         registration.properties = params 
@@ -90,8 +91,7 @@ class RegistrationController extends BaseController {
         } 
         else { 
             if(registration.save()) { 
-                flash.message =  
-                    &quot;Successfully registered for ${registration.race.name}&quot; 
+                flash.message = &quot;Successfully registered for ${registration.race.name}&quot; 
                 redirect(controller:'race',action:'search') 
             } 
             else { 
@@ -99,5 +99,5 @@ class RegistrationController extends BaseController {
                 return ['registration':registration,'race':race] 
             } 
         } 
-    } 
+    }  
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/controllers/RegistrationController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
             
 class UserController extends BaseController { 
     def beforeInterceptor = [action:this.&amp;auth, except:['login', 'logout']] 
-    
+
     def index = { redirect(action:list,params:params) }
 
     // the delete, save and update actions only</diff>
      <filename>racetrack_ch8/grails-app/controllers/UserController.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Race {  
+class Race { 
     String name 
     Date startDateTime 
     String city 
@@ -7,16 +7,16 @@ class Race {
     Float cost 
     Integer maxRunners = 100000 
      
-    static hasMany = [registrations:Registration]  
+    static hasMany = [registrations:Registration]
     
     static constraints = { 
-        name(maxLength:50,blank:false) 
-        startDateTime(validator: {return (it &gt; new Date())})  
-        city(maxLength:30,blank:false) 
+        name(maxSize:50,blank:false) 
+        startDateTime(validator: {return (it &gt; new Date())}) 
+        city(maxSize:30,blank:false) 
         state(inList:['GA', 'NC', 'SC', 'VA'],blank:false) 
         distance(min:3.1f,max:100f) 
         cost(min:0f,max:999.99f) 
-    }
+    } 
     
-    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot;}     
-}
\ No newline at end of file
+    String toString() {&quot;${this.name} : ${this.city}, ${this.state}&quot; }
+}	</diff>
      <filename>racetrack_ch8/grails-app/domain/Race.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-class Registration  {  
+class Registration { 
     Race race 
     String name 
     Date dateOfBirth 
@@ -6,19 +6,17 @@ class Registration  {
     String postalAddress 
     String emailAddress 
     Date createdAt = new Date() 
-    
+
     static belongsTo = Race 
-    
-    static optionals = [&quot;postalAddress&quot; ]  
-    
+
     static constraints = { 
-        name(maxLength:50,blank:false) 
+        name(maxSize:50,blank:false) 
         dateOfBirth(nullable:false) 
         gender(inList:[&quot;M&quot;, &quot;F&quot;]) 
-        postalAddress(maxLength:255) 
-        emailAddress(maxLength:50,email:true) 
+        postalAddress(nullable:true,maxSize:255) 
+        emailAddress(maxSize:50,email:true) 
         race(nullable:false) 
     } 
-
-  String toString() {&quot;${this.name} : ${this.emailAddress}&quot;}         
-}
\ No newline at end of file
+    
+    String toString(){&quot;${this.name}:${this.emailAddress}&quot;}         
+}	</diff>
      <filename>racetrack_ch8/grails-app/domain/Registration.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@ class User {
     String password 
  
     static constraints = { 
-        userId(length:6..8,unique:true) 
-        password(length:6..8) 
+        userId(size:6..8,unique:true) 
+        password(size:6..8) 
     } 
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/domain/User.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,29 +1,28 @@
 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.message=Property [{0}] of class [{1}] is not a valid [{2}].
+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.length.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}]
-default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}]
 default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}]
-default.invalid.max.length.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}]
-default.invalid.min.length.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{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.not.editable.message=Property [{0}] of class [{1}] with value [{2}] cannot be changed from [{3}] 
 
-race.name.blank=Please enter a name for this race 
+default.paginate.prev=Previous
+default.paginate.next=Next
+
+race.name.blank=Please enter a name for this race
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles 
 race.startDateTime.validator.invalid=Please enter a future date and time
 race.city.blank=Please enter a city for this race
-race.city.maxLength.exceeded=Please limit the city name to a maximum length of {3} characters
+race.city.maxSize.exceeded=Please limit the city name to a maximum length of {3} characters
 race.distance.nullable=Please enter a valid distance
 race.distance.min.notmet=Please enter a valid distance no fewer than {3} miles
 race.distance.max.exceeded=Please enter a valid distance no more than {3} miles
@@ -32,8 +31,8 @@ race.cost.min.notmet=Please enter a valid cost of at least ${3}
 race.cost.max.exceeded=Please enter a valid cost no more than ${3}
 
 registration.name.blank=Please enter a name
-registration.name.maxLength.exceeded=Please limit the name to a maximum length of {3} characters
-registration.postalAddress.maxLength.exceeded=Please limit the postal address to a maximum length of {3} characters
+registration.name.maxSize.exceeded=Please limit the name to a maximum length of {3} characters
+registration.postalAddress.maxSize.exceeded=Please limit the postal address to a maximum length of {3} characters
 registration.emailAddress.blank=Please enter an e-mail address
-registration.emailAddress.maxLength.exceeded=Please limit the e-mail address to a maximum length of {3} characters
+registration.emailAddress.maxSize.exceeded=Please limit the e-mail address to a maximum length of {3} characters
 registration.emailAddress.email.invalid=Please enter a valid e-mail address
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/i18n/messages.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,18 +1,22 @@
 &lt;g:if test=&quot;${!session.userId}&quot;&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;login&quot;&gt;Log in&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;login&quot;&gt;Log 
+in&lt;/g:link&gt; 
     &lt;/span&gt; 
 &lt;/g:if&gt; 
 &lt;g:else&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
         &lt;g:link controller=&quot;race&quot; action=&quot;list&quot;&gt; 
-            Manage Races &amp; Registrations 
+            Manage Races &amp;amp; Registrations 
         &lt;/g:link&gt; 
     &lt;/span&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;list&quot;&gt;Manage Administrators&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;list&quot;&gt;Manage Administrators 
+         &lt;/g:link&gt; 
     &lt;/span&gt; 
     &lt;span class=&quot;menuButton&quot;&gt; 
-        &lt;g:link controller=&quot;user&quot; action=&quot;logout&quot;&gt;Log out&lt;/g:link&gt; 
+        &lt;g:link controller=&quot;user&quot; action=&quot;logout&quot;&gt; 
+            Log out 
+        &lt;/g:link&gt; 
     &lt;/span&gt; 
 &lt;/g:else&gt; </diff>
      <filename>racetrack_ch8/grails-app/views/_adminmenubar.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -16,4 +16,4 @@
             &lt;/tr&gt; 
         &lt;/table&gt; 
     &lt;/body&gt; 
-&lt;/html&gt; 
+&lt;/html&gt; 
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/views/layouts/public.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -28,19 +28,19 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/race/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -31,19 +31,19 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${race?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='startDateTime'&gt;Start Date Time:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'startDateTime','errors')}'&gt;&lt;g:datePicker name='startDateTime' value=&quot;${race?.startDateTime}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='city'&gt;City:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'city','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='30' name='city' value=&quot;${race?.city?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='state'&gt;State:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'state','errors')}'&gt;&lt;g:select name='state' from='${race.constraints.state.inList.collect{it.encodeAsHTML()}}' value=&quot;${race.state?.encodeAsHTML()}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='distance'&gt;Distance (mi):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'distance','errors')}'&gt;&lt;input type='text' name='distance' value=&quot;${race?.distance}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='cost'&gt;Cost (US$):&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'cost','errors')}'&gt;&lt;input type='text' name='cost' value=&quot;${race?.cost}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='maxRunners'&gt;Max Runners:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'maxRunners','errors')}'&gt;&lt;input type='text' name='maxRunners' value=&quot;${race?.maxRunners}&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='registrations'&gt;Registrations:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:race,field:'registrations','errors')}'&gt;&lt;ul&gt;
     &lt;g:each var='r' in='${race?.registrations?}'&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/race/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New Race&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt; 
-                &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
+                    &lt;g:link action=&quot;search&quot;&gt;Search for Races&lt;/g:link&gt; 
             &lt;/span&gt; 
             &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
@@ -24,17 +24,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Start Date Time&lt;/th&gt;
-                                      
-                        &lt;th&gt;City&lt;/th&gt;
-                                      
-                        &lt;th&gt;State&lt;/th&gt;
-                                      
-                        &lt;th&gt;Distance&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;startDateTime&quot; title=&quot;Start Date Time&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;city&quot; title=&quot;City&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;state&quot; title=&quot;State&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;distance&quot; title=&quot;Distance&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/race/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,14 +1,15 @@
 &lt;html&gt; 
     &lt;head&gt; 
-        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt; 
+        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;  
+       charset=UTF-8&quot;/&gt; 
         &lt;meta name=&quot;layout&quot; content=&quot;public&quot; /&gt; 
         &lt;title&gt;Search for Races&lt;/title&gt; 
     &lt;/head&gt; 
     &lt;body&gt; 
-        &lt;div class=&quot;nav&quot;&gt; 
-            &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
-        &lt;/div&gt;
-        &lt;div class=&quot;body&quot;&gt; 
+      &lt;div class=&quot;nav&quot;&gt; 
+         &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
+      &lt;/div&gt; 
+      &lt;div class=&quot;body&quot;&gt; 
          &lt;h1&gt;Search for Races&lt;/h1&gt; 
          &lt;g:if test=&quot;${flash.message}&quot;&gt; 
              &lt;div class=&quot;message&quot;&gt;${flash.message}&lt;/div&gt; 
@@ -30,34 +31,37 @@
                        &lt;label for='state'&gt;State:&lt;/label&gt; 
                    &lt;/td&gt; 
                    &lt;td valign='top' class='value'&gt; 
-                       &lt;g:select name='state' from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
+                       &lt;g:select name='state'  
+                   from='${[&quot;&quot;] + new Race().constraints.state.inList}'&gt; 
                       &lt;/g:select&gt; 
                    &lt;/td&gt; 
                &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='date'&gt;Date:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         between 
-                         &lt;g:datePicker name='minDate' precision='day' /&gt; 
-                         and 
-                         &lt;g:datePicker name='maxDate' precision='day' value='${new Date().plus(365*2)}'/&gt; 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt; 
-                 &lt;tr class='prop'&gt; 
-                     &lt;td valign='top' class='name'&gt; 
-                         &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
-                     &lt;/td&gt; 
-                     &lt;td valign='top' class='value'&gt; 
-                         &lt;select name='distanceOperator' &gt; 
-                             &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
-                             &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
-                             &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
-                         &lt;/select&gt; 
-                         &lt;input type='text' name='distance' size='5'&gt;&lt;/input&gt; mi 
-                     &lt;/td&gt; 
-                 &lt;/tr&gt;               
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='date'&gt;Date:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     between 
+                     &lt;g:datePicker name='minDate' precision='day' /&gt; 
+                     and 
+                     &lt;g:datePicker name='maxDate' precision='day'  
+                  value='${new Date().plus(365*2)}'/&gt; 
+                 &lt;/td&gt; 
+             &lt;/tr&gt; 
+             &lt;tr class='prop'&gt; 
+                 &lt;td valign='top' class='name'&gt; 
+                     &lt;label for='distance'&gt;Distance:&lt;/label&gt; 
+                 &lt;/td&gt; 
+                 &lt;td valign='top' class='value'&gt; 
+                     &lt;select name='distanceOperator' &gt; 
+                         &lt;option value='AT_LEAST' &gt;At least&lt;/option&gt; 
+                         &lt;option value='EXACTLY' &gt;Exactly&lt;/option&gt; 
+                         &lt;option value='AT_MOST' &gt;At most&lt;/option&gt; 
+                     &lt;/select&gt; 
+                     &lt;input type='text' name='distance' size='5'&gt; 
+             &lt;/input&gt; mi 
+                 &lt;/td&gt; 
+             &lt;/tr&gt;
             &lt;/table&gt; 
             &lt;/div&gt; 
             &lt;div class=&quot;buttons&quot;&gt; </diff>
      <filename>racetrack_ch8/grails-app/views/race/search.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -84,4 +84,4 @@
             &lt;/div&gt; 
         &lt;/div&gt; 
     &lt;/body&gt; 
-&lt;/html&gt;
\ No newline at end of file
+&lt;/html&gt; </diff>
      <filename>racetrack_ch8/grails-app/views/race/searchresults.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
   
 &lt;html&gt;
     &lt;head&gt;
-         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
+         &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;  
          &lt;g:javascript library=&quot;racetrack&quot; /&gt;          
           &lt;meta name=&quot;layout&quot; content=&quot;main&quot; /&gt;
          &lt;title&gt;Show Race&lt;/title&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/race/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -25,10 +25,7 @@
                &lt;div class=&quot;dialog&quot;&gt;
                 &lt;table&gt;
                     &lt;tbody&gt;
-
-                       
-                       
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -36,12 +33,10 @@
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                                   &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='createdAt'&gt;Created At:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'createdAt','errors')}'&gt;&lt;g:datePicker name='createdAt' value=&quot;${registration?.createdAt}&quot;&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
-                       
                     &lt;/tbody&gt;
                &lt;/table&gt;
                &lt;/div&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/registration/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -31,7 +31,7 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='name'&gt;Name:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'name','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='name' value=&quot;${registration?.name?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='dateOfBirth'&gt;Date Of Birth:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'dateOfBirth','errors')}'&gt;&lt;g:datePicker name='dateOfBirth' value=&quot;${registration?.dateOfBirth}&quot; precision='day'&gt;&lt;/g:datePicker&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -39,7 +39,7 @@
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='postalAddress'&gt;Postal Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'postalAddress','errors')}'&gt;&lt;textarea rows='5' cols='40' name='postalAddress'&gt;${registration?.postalAddress?.encodeAsHTML()}&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='emailAddress'&gt;Email Address:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'emailAddress','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='50' name='emailAddress' value=&quot;${registration?.emailAddress?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
 				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='race'&gt;Race:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:registration,field:'race','errors')}'&gt;&lt;g:select optionKey=&quot;id&quot; from=&quot;${Race.list()}&quot; name='race.id' value=&quot;${registration?.race?.id}&quot;&gt;&lt;/g:select&gt;&lt;/td&gt;&lt;/tr&gt;
                        
@@ -51,7 +51,7 @@
 
                &lt;div class=&quot;buttons&quot;&gt;
                      &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Update&quot; /&gt;&lt;/span&gt;
-                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                     &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/div&gt;
             &lt;/g:form&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/registration/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -21,17 +21,17 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                        &lt;th&gt;Name&lt;/th&gt;
-                                      
-                        &lt;th&gt;Date Of Birth&lt;/th&gt;
-                                      
-                        &lt;th&gt;Gender&lt;/th&gt;
-                                      
-                        &lt;th&gt;Postal Address&lt;/th&gt;
-                                      
-                        &lt;th&gt;Email Address&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+                   	    &lt;g:sortableColumn property=&quot;name&quot; title=&quot;Name&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;dateOfBirth&quot; title=&quot;Date Of Birth&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;gender&quot; title=&quot;Gender&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;postalAddress&quot; title=&quot;Postal Address&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;emailAddress&quot; title=&quot;Email Address&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/registration/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -5,10 +5,10 @@
     &lt;title&gt;Register&lt;/title&gt; 
   &lt;/head&gt; 
   &lt;body&gt; 
+  &lt;div class=&quot;body&quot;&gt; 
       &lt;div class=&quot;nav&quot;&gt; 
           &lt;g:render template=&quot;/adminmenubar&quot; /&gt; 
       &lt;/div&gt;
-      &lt;div class=&quot;body&quot;&gt; 
       &lt;h1&gt;Register for ${race.name} &lt;/h1&gt; 
       &lt;em&gt;Start Date: 
         &lt;g:formatDate date=&quot;${race.startDateTime}&quot; format=&quot;EEE, MMM d, yyyy&quot;/&gt; 
@@ -89,4 +89,4 @@
       &lt;/g:form&gt; 
     &lt;/div&gt; 
   &lt;/body&gt; 
-&lt;/html&gt; 
\ No newline at end of file
+&lt;/html&gt; </diff>
      <filename>racetrack_ch8/grails-app/views/registration/register.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -78,7 +78,7 @@
                &lt;g:form controller=&quot;registration&quot;&gt;
                  &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;${registration?.id}&quot; /&gt;
                  &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Edit&quot; /&gt;&lt;/span&gt;
-                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRaceDelete();&quot;/&gt;&lt;/span&gt;
+                 &lt;span class=&quot;button&quot;&gt;&lt;g:actionSubmit value=&quot;Delete&quot; onclick=&quot;return warnBeforeRegistrationDelete();&quot; /&gt;&lt;/span&gt;
                &lt;/g:form&gt;
            &lt;/div&gt;
         &lt;/div&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/registration/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@
         &lt;div class=&quot;nav&quot;&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Create User&lt;/h1&gt;
@@ -27,9 +28,9 @@
 
                        
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+                                  &lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                &lt;/table&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/user/create.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+             &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Edit User&lt;/h1&gt;
@@ -33,9 +34,9 @@
 
                        
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='userId'&gt;User Id:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'userId','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='userId' value=&quot;${user?.userId?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
-				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;&gt;&lt;/input&gt;&lt;/td&gt;&lt;/tr&gt;
+				&lt;tr class='prop'&gt;&lt;td valign='top' class='name'&gt;&lt;label for='password'&gt;Password:&lt;/label&gt;&lt;/td&gt;&lt;td valign='top' class='value ${hasErrors(bean:user,field:'password','errors')}'&gt;&lt;input type=&quot;text&quot; maxlength='8' name='password' value=&quot;${user?.password?.encodeAsHTML()}&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;
                        
                     &lt;/tbody&gt;
                 &lt;/table&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/user/edit.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@
         &lt;div class=&quot;nav&quot;&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;User List&lt;/h1&gt;
@@ -20,15 +21,14 @@
            &lt;table&gt;
              &lt;thead&gt;
                &lt;tr&gt;
-                   
-                                      
-                        &lt;th&gt;Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;User Id&lt;/th&gt;
-                                      
-                        &lt;th&gt;Password&lt;/th&gt;
-                   
-                   &lt;th&gt;&lt;/th&gt;
+               
+                   	    &lt;g:sortableColumn property=&quot;id&quot; title=&quot;Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;userId&quot; title=&quot;User Id&quot; /&gt;
+                  
+                   	    &lt;g:sortableColumn property=&quot;password&quot; title=&quot;Password&quot; /&gt;
+                  
+                        &lt;th&gt;&lt;/th&gt;
                &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;tbody&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/user/list.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -44,4 +44,4 @@
             &lt;/g:form&gt; 
         &lt;/div&gt; 
     &lt;/body&gt; 
-&lt;/html&gt; 
+&lt;/html&gt; 
\ No newline at end of file</diff>
      <filename>racetrack_ch8/grails-app/views/user/login.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,7 @@
             &lt;span class=&quot;menuButton&quot;&gt;&lt;a href=&quot;${createLinkTo(dir:'')}&quot;&gt;Home&lt;/a&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;list&quot;&gt;User List&lt;/g:link&gt;&lt;/span&gt;
             &lt;span class=&quot;menuButton&quot;&gt;&lt;g:link action=&quot;create&quot;&gt;New User&lt;/g:link&gt;&lt;/span&gt;
+            &lt;g:render template=&quot;/adminmenubar&quot; /&gt;
         &lt;/div&gt;
         &lt;div class=&quot;body&quot;&gt;
            &lt;h1&gt;Show User&lt;/h1&gt;</diff>
      <filename>racetrack_ch8/grails-app/views/user/show.gsp</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ class RaceTests extends GroovyTestCase {
         def race = getValidRace() 
         race.name = 'It may very well take longer to type out the name of ' + 
             'this race than to just go run it.' 
-        assertValidationError(race, 'name', 'race.name.maxLength.exceeded') 
+        assertValidationError(race, 'name', 'race.name.maxSize.exceeded') 
     } 
      
     void testNameNullConstraint() {
@@ -48,7 +48,7 @@ class RaceTests extends GroovyTestCase {
     void testCityMaxConstraint() {
         def race = getValidRace()
         race.city = 'I pity the fool that lives in a city with a name this long.'
-        assertValidationError(race, 'city', 'race.city.maxLength.exceeded')
+        assertValidationError(race, 'city', 'race.city.maxSize.exceeded')
     }
 
     void testStateNullConstraint() {
@@ -84,7 +84,7 @@ class RaceTests extends GroovyTestCase {
     void testDistanceMaxConstraint() {
         def race = getValidRace()
         race.distance = 100.0001
-        assertValidationError(race, 'distance', 'race.distance.max.exceeded') // TODO Explain where to find the list of error codes - the validation reference page
+        assertValidationError(race, 'distance', 'race.distance.max.exceeded')
     }
 
     void testCostNullConstraint() {</diff>
      <filename>racetrack_ch8/grails-tests/RaceTests.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,10 @@ import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
-class ApplicationTagLib {
+class ApplicationTagLib { 
+	
+	def grailsUrlMappingsHolder
+	
     /**
      * Creates a link to a resource, generally used as a method rather than a tag.
      *
@@ -33,7 +36,7 @@ class ApplicationTagLib {
      */
     def createLinkTo = { attrs -&gt;
          out &lt;&lt; grailsAttributes.getApplicationUri(request)
-         if(attrs['dir']) {
+         if(attrs['dir'] || attrs['dir'] == '') {
             out &lt;&lt; &quot;/${attrs['dir']}&quot;
          }
          if(attrs['file']) {
@@ -50,7 +53,7 @@ class ApplicationTagLib {
     def link = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;a href=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // process remaining attributes
@@ -59,7 +62,7 @@ class ApplicationTagLib {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -79,29 +82,47 @@ class ApplicationTagLib {
         if(attrs['url']) {
              attrs = attrs.remove('url')
         }
-        // if the current attribute null set the controller uri to the current controller
-        if(attrs[&quot;controller&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;controller&quot;)
-        }
-        else {
-           out &lt;&lt; grailsAttributes.getControllerUri(request)
-        }
-        if(attrs[&quot;action&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;action&quot;)
-        }
-        if(attrs[&quot;id&quot;]) {
-            out &lt;&lt; '/' &lt;&lt; attrs.remove(&quot;id&quot;)
-        }
-        if(attrs['params']) {
-            def pms = attrs.remove('params')
-            out &lt;&lt; '?'
-            def i = 0
-            pms.each { k,v -&gt;
-                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
-                if(++i &lt; pms.size())
-                   out &lt;&lt; '&amp;'
-            }
-        }
+                                                     
+		def controller = attrs.containsKey(&quot;controller&quot;) ? attrs.remove(&quot;controller&quot;) : grailsAttributes.getController(request).controllerName
+		def action = attrs.remove(&quot;action&quot;)
+        def id = attrs.remove(&quot;id&quot;)
+        def params = attrs.params ? attrs.remove('params') : [:]
+
+        def url
+		try {
+            if(id) params.id = id
+            def mapping = grailsUrlMappingsHolder?.getReverseMapping(controller,action,params)
+			params.controller = controller
+			if(action) params.action = action  
+            url = mapping?.createURL(params)
+		}        
+		finally {
+			params.remove('controller')
+			params.remove('action')          
+			params.remove('id')
+		}
+		if(url) {
+			out &lt;&lt; url
+		}             
+		else {
+            out &lt;&lt; '/' &lt;&lt; controller
+	        if(action) {
+	            out &lt;&lt; '/' &lt;&lt; action
+	        }
+	        if(id) {
+	            out &lt;&lt; '/' &lt;&lt; id
+	        }
+	        if(params) {
+	            out &lt;&lt; '?'
+	            def i = 0
+	            params.each { k,v -&gt;
+	                out &lt;&lt; &quot;${k.encodeAsURL()}=${v?.encodeAsURL()}&quot;
+	                if(++i &lt; params.size())
+	                   out &lt;&lt; '&amp;'
+	            }
+	        }			
+		}
+															
     }
 
 	/**
@@ -127,8 +148,8 @@ class ApplicationTagLib {
 				} 				
 			}
 		}
-		out &lt;&lt; '&gt;'
-		body()
+		out &lt;&lt; '&gt;'  
+		out &lt;&lt; body()
 		out &lt;&lt; &quot;&lt;/${attrs.name}&gt;&quot;			
 	}	
 }</diff>
      <filename>racetrack_ch8/plugins/core/grails-app/taglib/ApplicationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -16,6 +16,7 @@ import org.springframework.validation.Errors;
 import org.springframework.context.NoSuchMessageException;
 import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
+import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
 
  /**
  *  A  tag lib that provides tags for working with form controls
@@ -33,7 +34,10 @@ class FormTagLib {
 	def textField = { attrs -&gt;
 		attrs.type = &quot;text&quot;  
 		attrs.tagName = &quot;textField&quot; 
-		field(attrs)
+		def result = field(attrs)
+		if(result) {     
+			out &lt;&lt; result
+		}
 	}
 	/**
 	 * Creates a hidden field
@@ -41,7 +45,7 @@ class FormTagLib {
 	def hiddenField = { attrs -&gt;
 		attrs.type = &quot;hidden&quot;
 		attrs.tagName = &quot;hiddenField&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * Creates a submit button
@@ -49,7 +53,7 @@ class FormTagLib {
 	def submitButton = { attrs -&gt;
 		attrs.type = &quot;submit&quot;
 		attrs.tagName = &quot;submitButton&quot;
-		field(attrs)
+		out &lt;&lt; field(attrs)
 	}
 	/**
 	 * A general tag for creating fields
@@ -84,7 +88,7 @@ class FormTagLib {
     void resolveAttributes(attrs)
     {
         if(!attrs.name &amp;&amp; !attrs.field) {
-            throwTagError(&quot;Tag [$tagName] is missing required attribute [name] or [field]&quot;)
+            throwTagError(&quot;Tag [${attrs.tagName}] is missing required attribute [name] or [field]&quot;)
         }
         attrs.remove('tagName')
 
@@ -121,7 +125,7 @@ class FormTagLib {
     def form = { attrs, body -&gt;
         out &lt;&lt; &quot;&lt;form action=\&quot;&quot;
         // create the link
-        createLink(attrs)
+        out &lt;&lt; createLink(attrs)
 
         out &lt;&lt; '\&quot; '
         // default to post
@@ -133,26 +137,34 @@ class FormTagLib {
 
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        def bodyContent = body()
+		out &lt;&lt; bodyContent
 
         // close tag
         out &lt;&lt; &quot;&lt;/form&gt;&quot;
     }
     /**
      * Creates a submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmit value=&quot;Edit&quot; /&gt;
+     *  &lt;g:actionSubmit action=&quot;Edit&quot; value=&quot;Some label for editing&quot; /&gt;
      *
      */
     def actionSubmit = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;submit&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+    	if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
-        // process remaining attributes
+
+		// add action and value
+		def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    	
+    	out &lt;&lt; &quot;&lt;input type=\&quot;submit\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+    	
+    	// process remaining attributes
         outputAttributes(attrs)
 
         // close tag
@@ -161,22 +173,30 @@ class FormTagLib {
     }
     /**
      * Creates a an image submit button that submits to an action in the controller specified by the form action
-     * The value of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
-     * &quot;edit&quot; or &quot;List People&quot; becomes &quot;listPeople&quot;
+     * The name of the action attribute is translated into the action name, for example &quot;Edit&quot; becomes
+     * &quot;_action_edit&quot; or &quot;List People&quot; becomes &quot;_action_listPeople&quot;
+     * If the action attribute is not specified, the value attribute will be used as part of the action name
      *
      *  &lt;g:actionSubmitImage src=&quot;/images/submitButton.gif&quot; action=&quot;Edit&quot; /&gt;
      *
      */
     def actionSubmitImage = { attrs -&gt;
-        out &lt;&lt; '&lt;input type=&quot;image&quot; name=&quot;_action&quot; '
-        def value = attrs.remove('value')
-        if(value) {
-             out &lt;&lt; &quot;value=\&quot;${value}\&quot; &quot;
+        if(!attrs.value) {
+            throwTagError(&quot;Tag [$tagName] is missing required attribute [value]&quot;)
         }
+        
+        // add action and value
+        def value = attrs.remove('value')
+		def action = attrs.action ? attrs.remove('action') : value
+    
+        out &lt;&lt; &quot;&lt;input type=\&quot;image\&quot; name=\&quot;_action_${action}\&quot; value=\&quot;${value}\&quot; &quot;
+
+		// add image src        
         def src = attrs.remove('src')
         if(src) {
              out &lt;&lt; &quot;src=\&quot;${src}\&quot; &quot;
         }
+
         // process remaining attributes
         outputAttributes(attrs)
 
@@ -201,6 +221,8 @@ class FormTagLib {
 
         def value = (attrs['value'] ? attrs['value'] : xdefault)
         def name = attrs['name']
+        def id = attrs['id'] ? attrs['id'] : name
+
 		def noSelection = attrs['noSelection']
 		if (noSelection != null)
 		{
@@ -253,7 +275,7 @@ class FormTagLib {
 
         // create day select
         if (precision &gt;= PRECISION_RANKINGS[&quot;day&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_day\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_day\&quot; id=\&quot;${id}_day\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -272,7 +294,7 @@ class FormTagLib {
 
         // create month select
         if (precision &gt;= PRECISION_RANKINGS[&quot;month&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_month\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_month\&quot; id=\&quot;${id}_month\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -294,7 +316,7 @@ class FormTagLib {
 
         // create year select
         if (precision &gt;= PRECISION_RANKINGS[&quot;year&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_year\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_year\&quot; id=\&quot;${id}_year\&quot;&gt;&quot;
 
             if (noSelection) {
     			renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -313,7 +335,7 @@ class FormTagLib {
 
         // do hour select
         if (precision &gt;= PRECISION_RANKINGS[&quot;hour&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_hour\&quot; id=\&quot;${id}_hour\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -338,7 +360,7 @@ class FormTagLib {
 
         // do minute select
         if (precision &gt;= PRECISION_RANKINGS[&quot;minute&quot;]) {
-            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot;&gt;&quot;
+            out.println &quot;&lt;select name=\&quot;${name}_minute\&quot; id=\&quot;${id}_minute\&quot;&gt;&quot;
 
             if (noSelection) {
 	    		renderNoSelectionOption( noSelection.key, noSelection.value, '')
@@ -360,7 +382,7 @@ class FormTagLib {
 	def renderNoSelectionOption = { noSelectionKey, noSelectionValue, value -&gt;
 		// If a label for the '--Please choose--' first item is supplied, write it out
         out &lt;&lt; '&lt;option value=&quot;' &lt;&lt; (noSelectionKey == null ? &quot;&quot; : noSelectionKey) &lt;&lt; '&quot;'
-        if(noSelectionKey == value) {
+        if(noSelectionKey.equals(value)) {
             out &lt;&lt; ' selected=&quot;selected&quot; '
         }
         out &lt;&lt; '&gt;' &lt;&lt; noSelectionValue.encodeAsHTML() &lt;&lt; '&lt;/option&gt;'
@@ -388,7 +410,7 @@ class FormTagLib {
         }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -405,7 +427,7 @@ class FormTagLib {
         attrs['optionValue'] = { &quot;${it.language}, ${it.country},  ${it.displayName}&quot; }
 
         // use generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -425,7 +447,7 @@ class FormTagLib {
 		   	attrs.value = null
 		}
         // invoke generic select
-        select( attrs )
+        out &lt;&lt; select( attrs )
     }
 
     /**
@@ -436,11 +458,15 @@ class FormTagLib {
      * &lt;g:select name=&quot;user.company.id&quot; from=&quot;${Company.list()}&quot; value=&quot;${user?.company.id}&quot; optionKey=&quot;id&quot; /&gt;
      */
     def select = { attrs -&gt;
+	    def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request)
+
         def from = attrs.remove('from')
         def keys = attrs.remove('keys')
         def optionKey = attrs.remove('optionKey')
         def optionValue = attrs.remove('optionValue')
         def value = attrs.remove('value')
+        def valueMessagePrefix = attrs.remove('valueMessagePrefix')
 		def noSelection = attrs.remove('noSelection')
         if (noSelection != null) {
             noSelection = noSelection.entrySet().iterator().next()
@@ -461,20 +487,21 @@ class FormTagLib {
         // create options from list
         if(from) {
             from.eachWithIndex { el,i -&gt;
+            	def keyValue = null
                 out &lt;&lt; '&lt;option '
                 if(keys) {
-                    out &lt;&lt; 'value=&quot;' &lt;&lt; keys[i] &lt;&lt; '&quot; '
-                    if(keys[i] == value) {
+                    keyValue = keys[i]
+                    out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
-               else if(optionKey) {
-                    def keyValue = null
+                else if(optionKey) {
                     if(optionKey instanceof Closure) {
                         keyValue = optionKey(el)
-                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
+                        out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
-                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getGrailsDomainClass(el.getClass().name)) {
+                    else if(el !=null &amp;&amp; optionKey == 'id' &amp;&amp; grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, el.getClass().name)) {
                         keyValue = el.ident()
                         out &lt;&lt; 'value=&quot;' &lt;&lt; keyValue &lt;&lt; '&quot; '
                     }
@@ -488,8 +515,9 @@ class FormTagLib {
                     }
                 }
                 else {
-                    out &lt;&lt; &quot;value=\&quot;${el}\&quot; &quot;
-                    if(el == value) {
+                	keyValue = el
+                    out &lt;&lt; &quot;value=\&quot;${keyValue}\&quot; &quot;
+                    if(keyValue == value) {
                         out &lt;&lt; 'selected=&quot;selected&quot; '
                     }
                 }
@@ -502,6 +530,19 @@ class FormTagLib {
                         out &lt;&lt; el.properties[optionValue].toString().encodeAsHTML()
                     }
                 }
+                else if(valueMessagePrefix) {
+                	def message = messageSource.getMessage(&quot;${valueMessagePrefix}.${keyValue}&quot;, null, null, locale)
+                	if(message) {
+                		out &lt;&lt; message.encodeAsHTML()
+                	}
+                	else if (keyValue) {
+                		out &lt;&lt; keyValue.encodeAsHTML()
+                	}
+					else {
+        	            def s = el.toString()
+    	                if(s) out &lt;&lt; s.encodeAsHTML()
+	                }
+                }
                 else {
                     def s = el.toString()
                     if(s) out &lt;&lt; s.encodeAsHTML()
@@ -554,6 +595,6 @@ class FormTagLib {
         outputAttributes(attrs)
 
         // close the tag, with no body
-        out &lt;&lt; ' &gt;&lt;/input&gt;'
+        out &lt;&lt; ' /&gt;'
      }
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch8/plugins/core/grails-app/taglib/FormTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -95,7 +95,7 @@ class JavascriptTagLib  {
 		}
 		else {
 			out.println '&lt;script type=&quot;text/javascript&quot;&gt;'
-				body()
+				out &lt;&lt; body()
 			out.println '&lt;/script&gt;'
 		}
 	}
@@ -137,15 +137,15 @@ class JavascriptTagLib  {
     /**
      * A link to a remote uri that used the prototype library to invoke the link via ajax
      */
-    def remoteLink = { attrs, body -&gt;
+    def remoteLink = { attrs, body -&gt;  
        out &lt;&lt; &quot;&lt;a href=\&quot;&quot;    
 
        def cloned = deepClone(attrs)
-	   createLink(cloned)               
+	   out &lt;&lt; createLink(cloned)               
 
 	   out &lt;&lt; &quot;\&quot; onclick=\&quot;&quot;
         // create remote function
-        remoteFunction(attrs)   
+        out &lt;&lt; remoteFunction(attrs)   
 		attrs.remove('url')
         out &lt;&lt; &quot;return false;\&quot; &quot;
         // process remaining attributes
@@ -154,7 +154,7 @@ class JavascriptTagLib  {
         }
         out &lt;&lt; &quot;&gt;&quot;
         // output the body
-        body()
+        out &lt;&lt; body()
 
         // close tag
         out &lt;&lt; &quot;&lt;/a&gt;&quot;
@@ -180,7 +180,7 @@ class JavascriptTagLib  {
 		else {
     		attrs.params = &quot;'${paramName}='+this.value&quot;			
 		}
-		remoteFunction(attrs)
+		out &lt;&lt; remoteFunction(attrs)
 		attrs.remove('params')
 		out &lt;&lt; &quot;\&quot;&quot;   
 		attrs.remove('url')
@@ -208,16 +208,16 @@ class JavascriptTagLib  {
 		// prepare form settings
 		prepareAjaxForm(p,attrs)
         
-        def params = [  onsubmit:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onsubmit:remoteFunction(attrs) + 'return false',
 					    method: (attrs.method? attrs.method : 'POST' ),
-					    action: (attrs.action? attrs.action : TagLibUtil.outToString(createLink,url))		                 
+					    action: (attrs.action? attrs.action : createLink(url))		                 
 		             ]
 		attrs.remove('url')		             
 	    params.putAll(attrs)
 		if(params.name &amp;&amp; !params.id)
 			params.id = params.name
-	    withTag(name:'form',attrs:params) {
-			body()   
+	    out &lt;&lt; withTag(name:'form',attrs:params) {
+			out &lt;&lt; body()   
 	    }		
     }
 
@@ -230,7 +230,7 @@ class JavascriptTagLib  {
 		// prepare form settings 
 		attrs.forSubmitTag = &quot;.form&quot;
 		prepareAjaxForm(p,attrs)    
-        def params = [  onclick:TagLibUtil.outToString(remoteFunction,attrs) + 'return false',
+        def params = [  onclick:remoteFunction(attrs) + 'return false',
 					    type: 'button',
 					    name: attrs.remove('name'),
 					    value: attrs.remove('value'), 
@@ -238,8 +238,8 @@ class JavascriptTagLib  {
 					    'class':attrs.remove('class')
 		             ]
 		             
-		withTag(name:'input', attrs:params) {
-			body()	
+		out &lt;&lt; withTag(name:'input', attrs:params) {
+			out &lt;&lt; body()	
 		}
     }
 	
@@ -275,7 +275,7 @@ class JavascriptTagLib  {
 			def sw = new StringWriter()
 			out = new PrintWriter(out)
 			// invoke body
-			body()
+			out &lt;&lt; body()
 			// restore out
 			out = tmp
 			js = sw.toString()
@@ -357,10 +357,10 @@ class PrototypeProvider implements JavascriptProvider {
 		
 		def pms = attrs.remove('params')   
 		if(attrs.url) {
-			taglib.createLink(attrs.url)			
+			out &lt;&lt; taglib.createLink(attrs.url)			
 		}                              
 		else {
-			taglib.createLink(attrs)			
+			out &lt;&lt; taglib.createLink(attrs)			
 		}
 
 		
@@ -415,6 +415,7 @@ class PrototypeProvider implements JavascriptProvider {
 	                    case 'true': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case 'false': ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    case ~/\s*function(\w*)\s*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
+	                    case ~/Insertion\..*/: ajaxOptions &lt;&lt; &quot;${k}:${v}&quot;; break;
 	                    default:ajaxOptions &lt;&lt; &quot;${k}:'${v}'&quot;; break;
 	                 }            	
             	}
@@ -441,10 +442,10 @@ class YahooProvider implements JavascriptProvider {
 		out &lt;&lt; &quot;YAHOO.util.Connect.asyncRequest('${method}','&quot;
 				
 		if(attrs.url) {
-			taglib.createLink(attrs.url)
+			out &lt;&lt; taglib.createLink(attrs.url)
 		}
 		else {
-			taglib.createLink(attrs)
+			out &lt;&lt; taglib.createLink(attrs)
 		}		
 		attrs.remove('url')
 		out &lt;&lt; &quot;',&quot;
@@ -504,7 +505,7 @@ class DojoProvider implements JavascriptProvider {
 		}		
 		 out &lt;&lt; 'dojo.io.bind({url:\''
 
-		 taglib.createLink(attrs) 
+		 out &lt;&lt; taglib.createLink(attrs) 
 		attrs.remove('params')
 		 out &lt;&lt; '\',load:function(type,data,evt) {'
 	    if(attrs.onLoaded) {</diff>
      <filename>racetrack_ch8/plugins/core/grails-app/taglib/JavascriptTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -25,6 +25,7 @@ import org.springframework.web.servlet.support.RequestContextUtils as RCU;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
 
 class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants {
+	def out // to facilitate testing
 
     protected getPage() {
     	return request[PAGE]
@@ -91,7 +92,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 				}
 			}
 			if(invokeBody) {
-				body();	
+				out &lt;&lt; body()
 			}
 		}
 	}
@@ -134,54 +135,183 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         if(attrs.total == null)
             throwTagError(&quot;Tag [paginate] is missing required attribute [total]&quot;)
 		
-		def mkp = new groovy.xml.MarkupBuilder(out)
+		def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+		def locale = RCU.getLocale(request) 
+		
 		def total = attrs.total.toInteger()
-		def max = params.max?.toInteger()
-		def offset = params.offset?.toInteger() 
 		def action = (attrs.action? attrs.action : 'list')
-		def breadcrumb = true
-		if(attrs.breadcrumb) breadcrumb = Boolean.valueOf(attrs.breadcrumb)
-			
+		def offset = params.offset?.toInteger()
+		def max = params.max?.toInteger()
+		def maxsteps = (attrs.maxsteps ? attrs.maxsteps.toInteger() : 10)
+
+        if(attrs.breadcrumb) {
+			log.warn(&quot;Tag [paginate] includes the [breadcrumb] attribute. This attribute is deprecated and will be removed in the future. Please update your code to use the [maxsteps] attribute instead.&quot;)
+		}
+
+		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)			
 		if(!max) max = (attrs.max ? attrs.max.toInteger() : 10)
-		if(!offset) offset = (attrs.offset ? attrs.offset.toInteger() : 0)
 		
-		def linkParams = [offset:offset-max,max:max]
-		def linkTagAttrs = ['class':'prevLink',action:action]
+		def linkParams = [offset:offset - max, max:max]
+		if(params.sort) linkParams.sort = params.sort
+		if(params.order) linkParams.order = params.order
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		def linkTagAttrs = [action:action]
 		if(attrs.controller) {
 			linkTagAttrs.controller = attrs.controller	
 		}
 		if(attrs.id) {
 			linkTagAttrs.id = attrs.id	
 		}
-		if(attrs.params)linkParams.putAll(attrs.params)
 		linkTagAttrs.params = linkParams
-	
-		def combined = max + offset
-		if(offset &gt; 0) {			
-			link(linkTagAttrs.clone(),{out&lt;&lt; (attrs.prev? attrs.prev : 'Previous' ) })
+		
+		// determine paging variables
+		def steps = maxsteps &gt; 0
+		int currentstep = (offset / max) + 1
+		int firststep = 1
+		int laststep = Math.round(Math.ceil(total / max))
+			
+		// display previous link when not on firststep
+		if(currentstep &gt; firststep) {
+			linkTagAttrs.class = 'prevLink'
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.prev ? attrs.prev : messageSource.getMessage('default.paginate.prev', null, 'Previous', locale))
+			 }
 		}
 		
-		if(total &gt; max) {
-			linkTagAttrs.'class' = 'step'
-			if(breadcrumb) {
-				def j = 0
-				0.step(total,max) { i -&gt;
-					if(offset == i) {
-						mkp.a('class':'step',&quot;${++j}&quot;)	
-					}
-					else {
-						linkParams.offset=i
-						link(linkTagAttrs.clone(),{out&lt;&lt;++j})	
-					}
-				}			
+		// display steps when steps are enabled and laststep is not firststep
+		if(steps &amp;&amp; laststep &gt; firststep) {
+			linkTagAttrs.class = 'step'
+
+			// determine begin and endstep paging variables
+			int beginstep = currentstep - Math.round(maxsteps / 2) + (maxsteps % 2)
+			int endstep = currentstep + Math.round(maxsteps / 2) - 1
+			
+			if(beginstep &lt; firststep) {
+				beginstep = firststep
+				endstep = maxsteps
+			}
+			if(endstep &gt; laststep) {
+				beginstep = laststep - maxsteps + 1
+				if(beginstep &lt; firststep) {
+					beginstep = firststep
+				}
+				endstep = laststep
+			}
+
+			// display firststep link when beginstep is not firststep
+			if(beginstep &gt; firststep) {
+				linkParams.offset = 0
+				out &lt;&lt; link(linkTagAttrs.clone()) {firststep.toString()}
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+			}
+
+			// display paginate steps
+			(beginstep..endstep).each { i -&gt;
+				if(currentstep == i) {
+					out &lt;&lt; &quot;&lt;span class=\&quot;currentStep\&quot;&gt;${i}&lt;/span&gt;&quot;
+				}
+				else {
+					linkParams.offset = (i - 1) * max
+					out &lt;&lt; link(linkTagAttrs.clone()) {i.toString()}
+				}
+			}	
+			
+			// display laststep link when endstep is not laststep
+			if(endstep &lt; laststep) {
+				out &lt;&lt; '&lt;span class=&quot;step&quot;&gt;..&lt;/span&gt;'
+				linkParams.offset = (laststep -1) * max
+				out &lt;&lt; link(linkTagAttrs.clone()) { laststep.toString() }
+			}		
+		}
+		
+		// display next link when not on laststep
+		if(currentstep &lt; laststep) {	
+			linkTagAttrs.class = 'nextLink'			
+			linkParams.offset = offset + max
+			out &lt;&lt; link(linkTagAttrs.clone()) {
+				(attrs.next ? attrs.next : messageSource.getMessage('default.paginate.next', null, 'Next', locale))
 			}			
 		}
-		linkParams.offset = offset+max
-		if(combined &lt; total) {	
-			linkTagAttrs.'class'='nextLink'			
-			link(linkTagAttrs,{out&lt;&lt; (attrs.'next'? attrs.'next' : 'Next' )})			
+
+	}
+
+	/**
+	 * Renders a sortable column to support sorting in list views
+	 *
+	 * Attributes:
+	 *
+	 * property - name of the property relating to the field
+	 * defaultOrder (optional) - default order for the property; choose between asc (default if not provided) and desc
+	 * title (optional*) - title caption for the column
+	 * titleKey (optional*) - title key to use for the column, resolved against the message source
+	 * params (optional) - a map containing request parameters
+	 *
+	 * Attribute title or titleKey is required. When both attributes are specified then titleKey takes precedence,
+	 * resulting in the title caption to be resolved against the message source. In case when the message could
+	 * not be resolved, the title will be used as title caption. 
+	 *
+	 * Examples:
+	 *
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; title=&quot;Title&quot; style=&quot;width: 200px&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;title&quot; titleKey=&quot;book.title&quot; /&gt;	 
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; /&gt;
+	 * &lt;g:sortableColumn property=&quot;releaseDate&quot; defaultOrder=&quot;desc&quot; title=&quot;Release Date&quot; titleKey=&quot;book.releaseDate&quot; /&gt;
+	 */
+	def sortableColumn = { attrs -&gt;
+
+		if(!attrs.property)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [property]&quot;) 
+		
+		if(!attrs.title &amp;&amp; !attrs.titleKey)
+			throwTagError(&quot;Tag [sortableColumn] is missing required attribute [title] or [titleKey]&quot;)
+
+		def property = attrs.remove(&quot;property&quot;)
+		def action = attrs.action ? attrs.remove(&quot;action&quot;) : &quot;list&quot;
+		
+		def defaultOrder = attrs.remove(&quot;defaultOrder&quot;)
+		if(defaultOrder != &quot;desc&quot;) defaultOrder = &quot;asc&quot;
+
+		// current sorting property and order
+		def sort = params.sort
+		def order = params.order
+
+		// add sorting property and params to link params
+		def linkParams = [sort:property]
+		if(attrs.params) linkParams.putAll(attrs.params)
+		
+		// determine and add sorting order for this column to link params
+		attrs.class = &quot;sortable&quot;
+		if(property == sort) {
+			attrs.class = attrs.class + &quot; sorted &quot; + order
+			if(order == &quot;asc&quot;) {
+				linkParams.order = &quot;desc&quot;
+			}
+			else {
+				linkParams.order = &quot;asc&quot;
+			}
+		}
+		else {
+			linkParams.order = defaultOrder
+		}
+
+		// determine column title
+		def title = attrs.remove(&quot;title&quot;)
+		def titleKey = attrs.remove(&quot;titleKey&quot;)
+		if(titleKey) {
+			if(!title) title = titleKey
+			def messageSource = grailsAttributes.getApplicationContext().getBean(&quot;messageSource&quot;)
+			def locale = RCU.getLocale(request)
+			title = messageSource.getMessage(titleKey, null, title, locale)
 		}
 
+		out &lt;&lt; &quot;&lt;th &quot;
+		// process remaining attributes
+		attrs.each { k, v -&gt;
+			out &lt;&lt; &quot;${k}=\&quot;${v.encodeAsHTML()}\&quot; &quot;
+		}
+		out &lt;&lt; &quot;&gt;${link(action:action, params:linkParams) { title }}&lt;/th&gt;&quot;
 	}
 
     /**
@@ -199,14 +329,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
         def uri = grailsAttributes.getTemplateUri(attrs.template,request)
         def var = attrs['var']
 
-        def url = servletContext.getResource(uri)
-        if(!url)
-            throwTagError(&quot;No template found for name [${attrs.template}] in tag [render]&quot;)
-
-        def t = engine.createTemplate(  uri,
-                                        servletContext,
-                                        request,
-                                        response)
+        def t = engine.createTemplate( uri )
 
         if(attrs.model instanceof Map) {
             t.make( attrs.model ).writeTo(out)
@@ -246,14 +369,7 @@ class RenderTagLib implements com.opensymphony.module.sitemesh.RequestConstants
 	        def engine = grailsAttributes.getPagesTemplateEngine()
 	        def uri = grailsAttributes.getTemplateUri(attrs.template,request)
 
-	        def url = servletContext.getResource(uri)
-	        if(!url)
-	            throwTagError(&quot;No template found for name [${attrs.template}] in tag [include]&quot;)
-
-	        def t = engine.createTemplate(  uri,
-	                                        servletContext,
-	                                        request,
-	                                        response)
+	        def t = engine.createTemplate(  uri )
 			
 			t.make().writeTo(out)
 		}</diff>
      <filename>racetrack_ch8/plugins/core/grails-app/taglib/RenderTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -152,7 +152,7 @@ class UITagLib {
 	 * &lt;g:richTextEditor name=&quot;editor&quot; height=&quot;400&quot; /&gt;
 	 */
 	def richTextEditor = { attrs -&gt;
-		withTag(name:'script',attributes:[type:'text/javascript']) {
+		out &lt;&lt; withTag(name:'script',attributes:[type:'text/javascript']) {
 			if(attrs.onComplete) {
 				out.println &quot;function FCKeditor_OnComplete( editorInstance ) {&quot;
 					out.println &quot;${attrs.onComplete}(editorInstance);&quot;					
@@ -162,24 +162,53 @@ class UITagLib {
 			var oFCKeditor = new FCKeditor( '${attrs.name}' ) ;
 			oFCKeditor.BasePath	 = \&quot;&quot;&quot;&quot;
 			if(attrs.basepath) {
-				createLinkTo(dir:attrs.basepath)
+				out &lt;&lt; createLinkTo(dir:attrs.basepath)
 			}
 			else {
-				createLinkTo(dir:&quot;fckeditor/&quot;)
+			    out &lt;&lt; createLinkTo(dir:&quot;fckeditor/&quot;)
 			}
 			out.println '&quot;;'
 			if(attrs.toolbar) {
 				out &lt;&lt; &quot;oFCKeditor.ToolbarSet	 = '${attrs.toolbar}';&quot; 	
-			}			
+			}
+			// add width support
+			if(attrs.width)			
+				out.println &quot;oFCKeditor.Width	= '${attrs.width}';&quot;
+			
 			if(attrs.height)			
-				out.println &quot;oFCKeditor.Height	= ${attrs.height};&quot;
+				out.println &quot;oFCKeditor.Height	= '${attrs.height}';&quot;
+			
+			// add skin support, values to choose: &quot;default&quot;, &quot;office2003&quot;, &quot;silver&quot;
+			if(attrs.skin)
+				out.println &quot;oFCKeditor.Config['SkinPath'] = 'skins/${attrs.skin}/';&quot;
+			
+			// check the browser compatibility when rendering the editor.  default value: true, values to choose: true, false, 
+			if(attrs.checkBrowser)
+				out.println &quot;oFCKeditor.CheckBrowser = ${attrs.checkBrowser};&quot;
+
+			// show error messages on errors while rendering the editor.   default value: true, values to choose: true, false
+			if(attrs.displayErrors)
+				out.println &quot;oFCKeditor.DisplayErrors = ${attrs.displayErrors};&quot;
+
+			// oFCKeditor.Config      AutoDetectLanguage:true/false, DefaultLanguage:'pt-BR' and so on
+			if(attrs.config) {
+				if (attrs.config instanceof Map) {
+					attrs.config.each { k, v -&gt;
+						out.println &quot;oFCKeditor.Config['$k'] = '$v';&quot;
+					}
+				} else {
+					throw new Exception(&quot;&quot;&quot;The format of config is not correct, it should be like &quot;[AutoDetectLanguage:false, DefaultLanguage:'pt-BR']&quot;   &quot;&quot;&quot;)
+				}
+			}
+
 			if(attrs.value) {
 				out &lt;&lt; &quot;oFCKeditor.Value	= \&quot;&quot;
-				escapeJavascript(Collections.EMPTY_MAP,attrs.value)
+			    out &lt;&lt; escapeJavascript(Collections.EMPTY_MAP,attrs.value)
 				out.println &quot;\&quot; ;&quot;
 			}
 			
-			out.println &quot;oFCKeditor.Create();&quot;			
+			out.println &quot;oFCKeditor.Create();&quot;	
+
 		}
 	}
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch8/plugins/core/grails-app/taglib/UITagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -32,9 +32,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def checkList = []
         if(model) {
-            checkList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors))
-            }
+            checkList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             checkList &lt;&lt; attrs['bean']
@@ -45,7 +43,7 @@ class ValidationTagLib {
 					if(ra) {
                         if(ra instanceof Errors)
                             checkList &lt;&lt; ra
-	                    else if ((ra.properties.errors) &amp;&amp; (ra.errors instanceof Errors)) {
+	                    else if (ra.properties?.errors instanceof Errors) {
                             checkList &lt;&lt; ra
 						}
 					}
@@ -55,23 +53,29 @@ class ValidationTagLib {
 
         for(i in checkList) {
             def errors = null
-            if(i instanceof Errors) {
+            if (i instanceof Errors) {
                errors = i
             }
-            else {
-				if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
-	                if (i.hasErrors())
-	                    errors = i.errors
-	            }
+            else {       
+				try {
+					if ((i.errors != null) &amp;&amp; (i.errors instanceof Errors)) {
+		                if (i.hasErrors())
+		                    errors = i.errors
+		            }
+					
+				}   
+				catch(MissingPropertyException mpe) {
+					// ignore
+				}
 			}
             if(errors) {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
-                        body()
+                        out &lt;&lt; body()
                     }
                 }
                 else {
-                    body()
+                    out &lt;&lt; body()
                 }
             }
         }
@@ -84,9 +88,7 @@ class ValidationTagLib {
         def model = attrs['model']
         def errorList = []
         if(model) {
-            errorList = model.findAll { k,v -&gt;
-                return ((v.errors != null) &amp;&amp; (v.errors instanceof Errors)) 
-            }
+            errorList = model.findAll { it.value?.errors instanceof Errors }.collect { it.value }
         }
         if(attrs['bean']) {
             errorList &lt;&lt; attrs['bean']
@@ -95,9 +97,9 @@ class ValidationTagLib {
             request.attributeNames.each {
                 def ra = request[it]
                 if(ra) {
-                    if(ra instanceof Errors)
+                    if (ra instanceof Errors)
                         errorList &lt;&lt; ra
-                    else if ((ra.errors != null) &amp;&amp; (ra.errors instanceof Errors)) {
+                    else if (ra.properties?.errors instanceof Errors) {
                         errorList &lt;&lt; ra
 					}
                 }
@@ -119,13 +121,13 @@ class ValidationTagLib {
                 if(attrs['field']) {
                     if(errors.hasFieldErrors(attrs['field'])) {
                         errors.getFieldErrors( attrs[&quot;field&quot;] ).each {
-                            body(it)
+                            out &lt;&lt; body(it)
                         }
                     }
                 }
                 else {
                     errors.allErrors.each {
-                        body( it )
+                        out &lt;&lt; body( it )
                     }
                 }
             }
@@ -141,9 +143,9 @@ class ValidationTagLib {
 
         if(renderAs == 'list') {
             out &lt;&lt; &quot;&lt;ul&gt;&quot;
-            eachError(attrs, {
+            out &lt;&lt; eachError(attrs, {
                 out &lt;&lt; &quot;&lt;li&gt;&quot;
-                message(error:it)
+                out &lt;&lt; message(error:it)
                 out &lt;&lt; &quot;&lt;/li&gt;&quot;
               }
             )
@@ -219,7 +221,7 @@ class ValidationTagLib {
         }
 
         def app = grailsAttributes.getGrailsApplication()
-        def dc = app.getGrailsDomainClass(againstClass)
+        def dc = app.getDomainClass(againstClass)
 
         if(!dc)
             throwTagError(&quot;Tag [validate] could not find a domain class to validate against for name [${againstClass}]&quot;)</diff>
      <filename>racetrack_ch8/plugins/core/grails-app/taglib/ValidationTagLib.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,7 @@ class URLCodec {
     }
 
     static decode = { obj -&gt;
-        URLEncoder.decode(obj.toString(), URLCodec.getEncoding())
+        URLDecoder.decode(obj.toString(), URLCodec.getEncoding())
     }
 
 	private static def getEncoding() {</diff>
      <filename>racetrack_ch8/plugins/core/grails-app/utils/URLCodec.groovy</filename>
    </modified>
    <modified>
      <diff>@@ -1,13 +1,7 @@
-CREATE USER SA PASSWORD &quot;&quot; ADMIN
-/*C1*/SET SCHEMA PUBLIC
+/*C4*/SET SCHEMA PUBLIC
 CONNECT USER SA
 DISCONNECT
-/*C2*/SET SCHEMA PUBLIC
+/*C5*/SET SCHEMA PUBLIC
 CONNECT USER SA
-/*C3*/SET SCHEMA PUBLIC
+/*C6*/SET SCHEMA PUBLIC
 CONNECT USER SA
-/*C2*/create table race (id bigint generated by default as identity (start with 1), version bigint not null, distance float not null, max_runners integer not null, start_date_time timestamp not null, state varchar(255) not null, cost float not null, name varchar(50) not null, city varchar(30) not null, primary key (id))
-create table registration (id bigint generated by default as identity (start with 1), version bigint not null, gender varchar(255) not null, date_of_birth timestamp not null, postal_address varchar(255), email_address varchar(50) not null, created_at timestamp not null, race_id bigint, name varchar(50) not null, primary key (id))
-create table user (id bigint generated by default as identity (start with 1), version bigint not null, password varchar(8) not null, user_id varchar(8) not null, primary key (id))
-alter table registration add constraint FKAF83E8B939D5A83A foreign key (race_id) references race
-INSERT INTO USER VALUES(1,0,'password','adminjoe')</diff>
      <filename>racetrack_ch8/prodDb.log</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 #HSQL Database Engine
-#Sun Mar 11 21:27:40 EDT 2007
+#Sat May 19 16:47:00 EDT 2007
 hsqldb.script_format=0
 runtime.gc_interval=0
 sql.enforce_strict_size=false</diff>
      <filename>racetrack_ch8/prodDb.properties</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch8/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,9 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 
-&lt;beans&gt;
 	&lt;bean id=&quot;grailsApplication&quot; class=&quot;org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean&quot;&gt;
 		&lt;description&gt;Grails application factory bean&lt;/description&gt;
 		&lt;property name=&quot;groovyFiles&quot;&gt;
@@ -25,7 +27,7 @@
         &lt;property name=&quot;pluginManager&quot; ref=&quot;pluginManager&quot; /&gt;
     &lt;/bean&gt;
 	
-    &lt;bean id=&quot;grailsResourceHolder&quot; singleton=&quot;false&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
+    &lt;bean id=&quot;grailsResourceHolder&quot; scope=&quot;prototype&quot; class=&quot;org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder&quot;&gt;
         &lt;property name=&quot;resources&quot;&gt;
               &lt;value&gt;classpath*:**/grails-app/**/*.groovy&lt;/value&gt;
         &lt;/property&gt;</diff>
      <filename>racetrack_ch8/web-app/WEB-INF/applicationContext.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,8 @@
 &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
-&lt;!DOCTYPE beans PUBLIC &quot;-//SPRING//DTD BEAN//EN&quot; &quot;http://www.springframework.org/dtd/spring-beans.dtd&quot;&gt;
-
-&lt;beans&gt;
+&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
+       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
+       xsi:schemaLocation=&quot;
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd&quot;&gt;
 	
 	
 &lt;/beans&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch8/web-app/WEB-INF/spring/resources.xml</filename>
    </modified>
    <modified>
      <diff>@@ -10,6 +10,254 @@
     &lt;uri&gt;http://grails.codehaus.org/tags&lt;/uri&gt;
 
     &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var}
+        &lt;/description&gt;
+        &lt;name&gt;set&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovySetTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Enables the storing of a value into the given ${var} into the page context
+        &lt;/description&gt;
+        &lt;name&gt;def&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyDefTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The value to store&lt;/description&gt;
+            &lt;name&gt;value&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The name of the variable to store the value in&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical if tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;if&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical else tag as fallback if the if condition fails
+        &lt;/description&gt;
+        &lt;name&gt;else&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;
+        	Logical elseif tag to test whether the given condition is true
+        &lt;/description&gt;
+        &lt;name&gt;elseif&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyElseIfTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;
+        	Tag to loop over a collection while the test expression returns true
+        &lt;/description&gt;
+        &lt;name&gt;while&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyWhileTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+            &lt;description&gt;The condition to test&lt;/description&gt;
+            &lt;name&gt;test&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;each&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyEachTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection&lt;/description&gt;
+        &lt;name&gt;findAll&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyFindAllTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to filter the elements to iterate over&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;true&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+	&lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and collects the elements
+        	you want to work with&lt;/description&gt;
+        &lt;name&gt;collect&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyCollectTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The expression to use to collect the elements. The
+        	expression must retur true to add the element to the
+        	collection&lt;/description&gt;
+            &lt;name&gt;expr&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;Iterates over the given collection and filters the elements
+        with a regular expression&lt;/description&gt;
+        &lt;name&gt;grep&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyGrepTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The collection to iterate over&lt;/description&gt;
+            &lt;name&gt;in&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;An optional var-name to reference onto the elements&lt;/description&gt;
+            &lt;name&gt;var&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The regular expression to filter the element with. The
+        	filter is a simple Groovy Regex&lt;/description&gt;
+            &lt;name&gt;filter&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+            &lt;name&gt;status&lt;/name&gt;
+            &lt;required&gt;false&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
+        &lt;description&gt;A tag that attempts to render an input for a bean property
+        into an appropriate component based on the type. It uses the templates
+        defined in &quot;grails-app/views/scaffolding&quot; to achieve this by looking up
+		the template by type.&lt;/description&gt;
+        &lt;name&gt;renderInput&lt;/name&gt;
+        &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.GroovyRenderInputTag&lt;/tag-class&gt;
+        &lt;body-content&gt;JSP&lt;/body-content&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The Bean to render the input for&lt;/description&gt;
+            &lt;name&gt;bean&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;attribute&gt;
+        	&lt;description&gt;The property of the bean to render input for&lt;/description&gt;
+            &lt;name&gt;property&lt;/name&gt;
+            &lt;required&gt;true&lt;/required&gt;
+            &lt;rtexprvalue&gt;true&lt;/rtexprvalue&gt;
+        &lt;/attribute&gt;
+        &lt;dynamic-attributes&gt;false&lt;/dynamic-attributes&gt;
+    &lt;/tag&gt;
+
+    &lt;tag&gt;
         &lt;name&gt;link&lt;/name&gt;
         &lt;tag-class&gt;org.codehaus.groovy.grails.web.taglib.jsp.JspLinkTag&lt;/tag-class&gt;
         &lt;body-content&gt;JSP&lt;/body-content&gt;</diff>
      <filename>racetrack_ch8/web-app/WEB-INF/tld/grails.tld</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
 &lt;web-app version=&quot;2.4&quot;
          xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
          xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</diff>
      <filename>racetrack_ch8/web-app/WEB-INF/web.template.xml</filename>
    </modified>
    <modified>
      <diff>@@ -1 +1 @@
-&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/base/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/user/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/registration/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;/race/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file
+&lt;web-app xsi:schemaLocation='http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd' version='2.4' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://java.sun.com/xml/ns/j2ee'&gt;&lt;context-param&gt;&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/classes/log4j.properties&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;context-param&gt;&lt;param-name&gt;webAppRootKey&lt;/param-name&gt;&lt;param-value&gt;racetrack&lt;/param-value&gt;&lt;/context-param&gt;&lt;filter&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;&lt;init-param&gt;&lt;param-name&gt;targetBeanName&lt;/param-name&gt;&lt;param-value&gt;characterEncodingFilter&lt;/param-value&gt;&lt;/init-param&gt;&lt;init-param&gt;&lt;param-name&gt;targetFilterLifecycle&lt;/param-name&gt;&lt;param-value&gt;true&lt;/param-value&gt;&lt;/init-param&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;filter-class&gt;org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;charEncodingFilter&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;grailsWebRequest&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;filter-mapping&gt;&lt;filter-name&gt;urlMapping&lt;/filter-name&gt;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;&lt;listener&gt;&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;listener&gt;&lt;listener-class&gt;org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet&lt;/servlet-class&gt;&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;servlet-class&gt;org.codehaus.groovy.grails.web.pages.GroovyPagesServlet&lt;/servlet-class&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;gsp&lt;/servlet-name&gt;&lt;url-pattern&gt;*.gsp&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;servlet-mapping&gt;&lt;servlet-name&gt;grails&lt;/servlet-name&gt;&lt;url-pattern&gt;*.dispatch&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;&lt;welcome-file-list&gt;&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;&lt;welcome-file&gt;index.gsp&lt;/welcome-file&gt;&lt;/welcome-file-list&gt;&lt;jsp-config&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/core&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/c.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://java.sun.com/jsp/jstl/fmt&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/fmt.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://www.springframework.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/spring.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;taglib&gt;&lt;taglib-uri&gt;http://grails.codehaus.org/tags&lt;/taglib-uri&gt;&lt;taglib-location&gt;/WEB-INF/tld/grails.tld&lt;/taglib-location&gt;&lt;/taglib&gt;&lt;/jsp-config&gt;&lt;/web-app&gt;
\ No newline at end of file</diff>
      <filename>racetrack_ch8/web-app/WEB-INF/web.xml</filename>
    </modified>
    <modified>
      <diff>@@ -124,4 +124,15 @@ td .errors {
 .prop .value {
 	text-align:left;
 	width:80%;
+}
+
+.prevLink, .step, .currentStep, .nextLink {
+	padding-right: 5px;
+}
+.currentStep {
+	font-weight:bold;
+}
+
+th.sorted a, th.sorted a:link, th.sorted a:visited, th.sorted a:hover, th.sortable a, th.sortable a:link, th.sortable a:visited, th.sortable a:hover {
+	color: white;
 }
\ No newline at end of file</diff>
      <filename>racetrack_ch8/web-app/css/main.css</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 function warnBeforeRaceDelete() { 
      return confirm('Are you sure you want to delete this race?') 
-}
+} 
 
 function warnBeforeRegistrationDelete() { 
      return confirm('Are you sure you want to delete this registration?') 
-}
\ No newline at end of file
+} </diff>
      <filename>racetrack_ch8/web-app/js/racetrack.js</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>racetrack_ch3/plugins/core/grails-app/taglib/TagLibUtil.groovy</filename>
    </removed>
    <removed>
      <filename>racetrack_ch3/web-app/index.jsp</filename>
    </removed>
    <removed>
      <filename>racetrack_ch4/plugins/core/grails-app/taglib/TagLibUtil.groovy</filename>
    </removed>
    <removed>
      <filename>racetrack_ch4/web-app/index.jsp</filename>
    </removed>
    <removed>
      <filename>racetrack_ch5/plugins/core/grails-app/taglib/TagLibUtil.groovy</filename>
    </removed>
    <removed>
      <filename>racetrack_ch5/web-app/index.jsp</filename>
    </removed>
    <removed>
      <filename>racetrack_ch6/plugins/core/grails-app/taglib/TagLibUtil.groovy</filename>
    </removed>
    <removed>
      <filename>racetrack_ch6/web-app/index.jsp</filename>
    </removed>
    <removed>
      <filename>racetrack_ch7/plugins/core/grails-app/taglib/TagLibUtil.groovy</filename>
    </removed>
    <removed>
      <filename>racetrack_ch7/web-app/index.jsp</filename>
    </removed>
    <removed>
      <filename>racetrack_ch8/jboss/log4j.xml</filename>
    </removed>
    <removed>
      <filename>racetrack_ch8/plugins/core/grails-app/taglib/TagLibUtil.groovy</filename>
    </removed>
    <removed>
      <filename>racetrack_ch8/racetrack.war</filename>
    </removed>
    <removed>
      <filename>racetrack_ch8/web-app/index.jsp</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>c6a98d59cd15bd7cef72be30154b4e698e07850a</id>
    </parent>
  </parents>
  <author>
    <name>Jason Rudolph</name>
    <email>jason@thinkrelevance.com</email>
  </author>
  <url>http://github.com/jasonrudolph/racetrack/commit/2c0585bd9ee003ce61e78dee8774236d0ce6f7d0</url>
  <id>2c0585bd9ee003ce61e78dee8774236d0ce6f7d0</id>
  <committed-date>2008-09-01T20:39:02-07:00</committed-date>
  <authored-date>2008-09-01T20:39:02-07:00</authored-date>
  <message>RaceTrack application built with Grails 0.5</message>
  <tree>0ca710a891ba7ed4cb2121f02d92a3effb3ffe86</tree>
  <committer>
    <name>Jason Rudolph</name>
    <email>jason@thinkrelevance.com</email>
  </committer>
</commit>
