[Tynstep-svn] r195 - in trunk/step: step-core step-core/src/main/java/com/tyndalehouse/step/core step-core/src/main/java/com/tyndalehouse/step/core/exceptions step-core/src/main/java/com/tyndalehouse/step/core/guice step-core/src/main/java/com/tyndalehouse/step/core/guice/providers step-core/src/main/java/com/tyndalehouse/step/core/models step-core/src/main/java/com/tyndalehouse/step/core/service step-core/src/main/java/com/tyndalehouse/step/core/service/impl step-core/src/main/java/com/tyndalehouse/step/core/utils step-core/src/main/java/com/tyndalehouse/step/core/xsl step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl step-core/src/main/resources step-core/src/main/resources/com/tyndalehouse/step/core step-core/src/main/resources/com/tyndalehouse/step/core/service/impl step-core/src/test/java/com/tyndalehouse/step/core/service step-core/src/test/java/com/tyndalehouse/step/core/service/impl step-core/src/test/java/com/tyndalehouse/step/core/utils step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl step-parent step-server step-server/src/main/java/com/tyndalehouse/step/server step-web step-web/src step-web/src/main/java/com/tyndalehouse/step step-web/src/main/java/com/tyndalehouse/step/guice step-web/src/main/java/com/tyndalehouse/step/rest step-web/src/main/java/com/tyndalehouse/step/rest/controllers step-web/src/main/java/com/tyndalehouse/step/rest/framework step-web/src/main/java/com/tyndalehouse/step/rest/wrappers step-web/src/main/webapp step-web/src/main/webapp/WEB-INF step-web/src/main/webapp/css step-web/src/main/webapp/js step-web/src/test step-web/src/test/java step-web/src/test/java/com step-web/src/test/java/com/tyndalehouse step-web/src/test/java/com/tyndalehouse/step step-web/src/test/java/com/tyndalehouse/step/rest step-web/src/test/java/com/tyndalehouse/step/rest/controllers

ChrisBurrell at crosswire.org ChrisBurrell at crosswire.org
Sun Dec 19 04:27:36 MST 2010


Author: ChrisBurrell
Date: 2010-12-19 04:27:36 -0700 (Sun, 19 Dec 2010)
New Revision: 195

Added:
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultLexiconRefsProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultVersionsProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/JSwordUtils.java
   trunk/step/step-core/src/main/resources/step.core.properties
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/SetupController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cached.java
   trunk/step/step-web/src/main/webapp/css/setup-layout.css
   trunk/step/step-web/src/main/webapp/js/setup.js
   trunk/step/step-web/src/main/webapp/setup.jsp
   trunk/step/step-web/src/test/
   trunk/step/step-web/src/test/java/
   trunk/step/step-web/src/test/java/com/
   trunk/step/step-web/src/test/java/com/tyndalehouse/
   trunk/step/step-web/src/test/java/com/tyndalehouse/step/
   trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/
   trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/
   trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java
Removed:
   trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/config/
   trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_default.xsl
   trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_interlinear.xsl
Modified:
   trunk/step/step-core/pom.xml
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/exceptions/StepInternalException.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/Definition.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/ModuleService.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImpl.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/XslHelper.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/MultiInterlinearProvider.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java
   trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/MultiInterlinearProviderImpl.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImplTest.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/utils/StringConversionUtilsTest.java
   trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java
   trunk/step/step-parent/pom.xml
   trunk/step/step-server/pom.xml
   trunk/step/step-server/src/main/java/com/tyndalehouse/step/server/StepServer.java
   trunk/step/step-web/pom.xml
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java
   trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java
   trunk/step/step-web/src/main/webapp/WEB-INF/web.xml
   trunk/step/step-web/src/main/webapp/index.jsp
   trunk/step/step-web/src/main/webapp/js/bookmark.js
   trunk/step/step-web/src/main/webapp/js/init.js
   trunk/step/step-web/src/main/webapp/js/lexicon_definition.js
   trunk/step/step-web/src/main/webapp/js/passage.js
   trunk/step/step-web/src/main/webapp/js/passage_toolbar.js
   trunk/step/step-web/src/main/webapp/js/ui_hooks.js
Log:


Modified: trunk/step/step-core/pom.xml
===================================================================
--- trunk/step/step-core/pom.xml	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/pom.xml	2010-12-19 11:27:36 UTC (rev 195)
@@ -23,11 +23,6 @@
 		</dependency>
 
 		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-context</artifactId>
-		</dependency>
-
-		<dependency>
 			<groupId>org.slf4j</groupId>
 			<artifactId>slf4j-api</artifactId>
 		</dependency>
@@ -41,7 +36,12 @@
 			<groupId>org.crosswire</groupId>
 			<artifactId>jsword</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.jdom</groupId>
+			<artifactId>jdom</artifactId>
+		</dependency>
 		
+		
 		<!-- common utils -->
 		<dependency>
 			<groupId>commons-beanutils</groupId>
@@ -53,6 +53,14 @@
 			<artifactId>commons-lang</artifactId>
 		</dependency>
 		
+		<dependency>
+			<groupId>commons-collections</groupId>
+			<artifactId>commons-collections</artifactId>
+		</dependency>
 		
+		<dependency>
+			<groupId>com.jolira</groupId>
+			<artifactId>guice</artifactId>
+		</dependency>
 	</dependencies>
 </project>

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/exceptions/StepInternalException.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/exceptions/StepInternalException.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/exceptions/StepInternalException.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,5 +1,12 @@
 package com.tyndalehouse.step.core.exceptions;
 
+/**
+ * The default exception to be thrown throughout the application. It is of type {@link RuntimeException} so that it does
+ * not require explicit catching
+ * 
+ * @author Chris
+ * 
+ */
 public class StepInternalException extends RuntimeException {
     private static final long serialVersionUID = -5636677138385910988L;
 

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/StepCoreModule.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,68 @@
+package com.tyndalehouse.step.core.guice;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.crosswire.jsword.book.install.Installer;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
+import com.google.inject.name.Names;
+import com.tyndalehouse.step.core.guice.providers.DefaultInstallersProvider;
+import com.tyndalehouse.step.core.guice.providers.DefaultLexiconRefsProvider;
+import com.tyndalehouse.step.core.guice.providers.DefaultVersionsProvider;
+import com.tyndalehouse.step.core.service.BibleInformationService;
+import com.tyndalehouse.step.core.service.JSwordService;
+import com.tyndalehouse.step.core.service.ModuleService;
+import com.tyndalehouse.step.core.service.impl.BibleInformationServiceImpl;
+import com.tyndalehouse.step.core.service.impl.JSwordServiceImpl;
+import com.tyndalehouse.step.core.service.impl.ModuleServiceImpl;
+
+/**
+ * The module configuration that configures the application via guice
+ * 
+ * @author Chris
+ * 
+ */
+public class StepCoreModule extends AbstractModule implements Module {
+    private static final String CORE_GUICE_PROPERTIES = "/step.core.properties";
+
+    @Override
+    protected void configure() {
+        bind(Properties.class).annotatedWith(Names.named("StepCoreProperties")).toInstance(readProperties());
+
+        bind(JSwordService.class).to(JSwordServiceImpl.class).asEagerSingleton();
+        bind(BibleInformationService.class).to(BibleInformationServiceImpl.class).asEagerSingleton();
+        bind(ModuleService.class).to(ModuleServiceImpl.class).asEagerSingleton();
+
+        bind(new TypeLiteral<List<String>>() {
+        }).annotatedWith(Names.named("defaultVersions")).toProvider(DefaultVersionsProvider.class);
+        bind(new TypeLiteral<Map<String, String>>() {
+        }).annotatedWith(Names.named("defaultLexiconRefs")).toProvider(DefaultLexiconRefsProvider.class);
+        bind(new TypeLiteral<List<Installer>>() {
+        }).toProvider(DefaultInstallersProvider.class);
+    }
+
+    /**
+     * reads the core properties from the file
+     * 
+     * @return a list of properties read from file
+     */
+    private Properties readProperties() {
+        final InputStream stream = getClass().getResourceAsStream(CORE_GUICE_PROPERTIES);
+        final Properties appProperties = new Properties();
+        try {
+            appProperties.load(stream);
+            Names.bindProperties(super.binder(), appProperties);
+        } catch (final IOException e) {
+            // This is the preferred way to tell Guice something went wrong
+            super.addError(e);
+        }
+        return appProperties;
+    }
+
+}

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultInstallersProvider.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,73 @@
+package com.tyndalehouse.step.core.guice.providers;
+
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.crosswire.jsword.book.install.Installer;
+import org.crosswire.jsword.book.install.sword.HttpSwordInstaller;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.tyndalehouse.step.core.exceptions.StepInternalException;
+
+/**
+ * Provides a set of installers for installing Bibles, modules, etc e.g. from Crosswire
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
+public class DefaultInstallersProvider implements Provider<List<Installer>> {
+    private final List<Installer> installers;
+
+    /**
+     * @param stepProperties the properties for the whole STEP application
+     * @param proxyHost the host name of the proxy
+     * @param proxyPort the port of a proxy to go through
+     */
+    @Inject
+    public DefaultInstallersProvider(@Named("StepCoreProperties") final Properties stepProperties,
+            @Named("app.proxy.host") final String proxyHost, @Named("app.proxy.port") final String proxyPort) {
+        this.installers = new ArrayList<Installer>();
+        final Set<Entry<Object, Object>> entrySet = stepProperties.entrySet();
+        for (final Entry<Object, Object> entry : entrySet) {
+            if (entry.getKey() instanceof String && ((String) entry.getKey()).startsWith("installer")) {
+                // add to list
+                final String[] split = StringUtils.split(entry.getValue().toString(), ",");
+
+                final HttpSwordInstaller installer = new HttpSwordInstaller();
+                installer.setHost(split[0]);
+                installer.setPackageDirectory(split[1]);
+                installer.setCatalogDirectory(split[2]);
+
+                if (isNotBlank(proxyHost)) {
+                    installer.setProxyHost(proxyHost);
+                }
+
+                if (isNotBlank(proxyPort)) {
+                    try {
+                        final Integer p = Integer.parseInt(proxyPort);
+                        installer.setProxyPort(p.intValue());
+                    } catch (final NumberFormatException e) {
+                        throw new StepInternalException("Unable to parse port number " + proxyPort, e);
+                    }
+                }
+
+                this.installers.add(installer);
+            }
+        }
+    }
+
+    @Override
+    public List<Installer> get() {
+        return this.installers;
+    }
+}

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultLexiconRefsProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultLexiconRefsProvider.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultLexiconRefsProvider.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,31 @@
+package com.tyndalehouse.step.core.guice.providers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.inject.Provider;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+
+/**
+ * Provides the mappings between lexicon key references and the module initials that should be used.
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
+public class DefaultLexiconRefsProvider implements Provider<Map<String, String>> {
+
+    /**
+     * @return the list of default versions to be installed on a STEP installation
+     * 
+     */
+    @Provides
+    public Map<String, String> get() {
+        final Map<String, String> moduleRefs = new HashMap<String, String>();
+        moduleRefs.put("strong:H", "StrongsHebrew");
+        moduleRefs.put("strong:G", "StrongsGreek");
+        moduleRefs.put("robinson:", "Robinson");
+        return moduleRefs;
+    }
+}

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultVersionsProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultVersionsProvider.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DefaultVersionsProvider.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,33 @@
+package com.tyndalehouse.step.core.guice.providers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.inject.Provider;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+
+/**
+ * Provides a list of default versions that should be installed for the application
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
+public class DefaultVersionsProvider implements Provider<List<String>> {
+
+    /**
+     * @return the list of default versions to be installed on a STEP installation
+     * 
+     */
+    @Provides
+    public List<String> get() {
+        final List<String> versions = new ArrayList<String>();
+        versions.add("ESV");
+        versions.add("KJV");
+        versions.add("StrongsHebrew");
+        versions.add("StrongsGreek");
+        versions.add("Byz");
+        return versions;
+    }
+}

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -15,10 +15,16 @@
     private String language;
     private boolean hasStrongs;
 
+    /**
+     * @return true if the version contains strong-tagged information
+     */
     public boolean isHasStrongs() {
         return this.hasStrongs;
     }
 
+    /**
+     * @param hasStrongs true if the version contains strong information
+     */
     public void setHasStrongs(final boolean hasStrongs) {
         this.hasStrongs = hasStrongs;
     }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/Definition.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/Definition.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/Definition.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -9,6 +9,12 @@
     private final String key;
     private final String explanation;
 
+    /**
+     * A definition is made up of a key and an explanation
+     * 
+     * @param key a key identifying where the definition came from
+     * @param explanation an explanation
+     */
     public Definition(final String key, final String explanation) {
         this.key = key;
         this.explanation = explanation;

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -11,10 +11,12 @@
  * 
  */
 public enum LookupOption {
+    // CHECKSTYLE:OFF TODO change the values in the XSL file
     /**
      * Showing headings
      */
     HEADINGS("Headings", "Headings", XslConversionType.DEFAULT, true),
+    // CHECKSTYLE:ON
     /**
      * Showing headings
      */
@@ -24,11 +26,12 @@
 
     /** Morphology */
     MORPHOLOGY("Morph", "Morphology", XslConversionType.INTERLINEAR),
+    // CHECKSTYLE:OFF
     /**
      * Interlinears are available when Strongs are available.
      */
     INTERLINEAR("Interlinear", "Interlinear", XslConversionType.INTERLINEAR),
-
+    // CHECKSTYLE:ON
     /**
      * Showing headings
      */
@@ -61,7 +64,8 @@
      * @param stylesheet the stylesheet to use
      * @param displayName the name to display on the user interface
      */
-    private LookupOption(final String xsltParameterName, final String displayName, final XslConversionType stylesheet) {
+    private LookupOption(final String xsltParameterName, final String displayName,
+            final XslConversionType stylesheet) {
         this(xsltParameterName, displayName, stylesheet, false);
     }
 
@@ -71,8 +75,8 @@
      * @param displayName the name to display on the user interface
      * @param enabledByDefault true to have the UI display the option by default
      */
-    private LookupOption(final String xsltParameterName, final String displayName, final XslConversionType stylesheet,
-            final boolean enabledByDefault) {
+    private LookupOption(final String xsltParameterName, final String displayName,
+            final XslConversionType stylesheet, final boolean enabledByDefault) {
         this.xsltParameterName = xsltParameterName;
         this.displayName = displayName;
         this.stylesheet = stylesheet;
@@ -86,10 +90,16 @@
         return this.xsltParameterName;
     }
 
+    /**
+     * @return the display name of the lookup option
+     */
     public String getDisplayName() {
         return this.displayName;
     }
 
+    /**
+     * @return the stylesheet that should be used
+     */
     public XslConversionType getStylesheet() {
         return this.stylesheet;
     }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -7,8 +7,8 @@
 import com.tyndalehouse.step.core.models.LookupOption;
 
 /**
- * Interface to the service that gives information about the books of the bible, the different types of bible, etc. This
- * service will mainly use JSword but may also rely on other data sources to display text.
+ * Interface to the service that gives information about the books of the bible, the different types of bible,
+ * etc. This service will mainly use JSword but may also rely on other data sources to display text.
  * 
  * @author Chris
  * 
@@ -16,15 +16,15 @@
 public interface BibleInformationService {
 
     /**
-     * Queries Jsword to return all the available versions of the bible
+     * Queries Jsword to return all the installed versions of the bible
      * 
      * @return all the available versions of the bible
      */
-    List<BibleVersion> getBibleVersions();
+    List<BibleVersion> getAvailableBibleVersions();
 
     /**
-     * This method selects passage text and forms XML for the client. This is done server side so that the client does
-     * not need to render each div individually.
+     * This method selects passage text and forms XML for the client. This is done server side so that the
+     * client does not need to render each div individually.
      * 
      * @param version the initials that identify the bible version
      * @param reference the reference
@@ -32,7 +32,8 @@
      * @param interlinearVersion version to use as the interlinear
      * @return the HTML string passed back for consumption
      */
-    String getPassageText(String version, String reference, List<LookupOption> lookupOptions, String interlinearVersion);
+    String getPassageText(String version, String reference, List<LookupOption> lookupOptions,
+            String interlinearVersion);
 
     /**
      * 
@@ -44,8 +45,26 @@
     /**
      * Gets a list of all supported features so far
      * 
-     * @return
+     * @return the list of lookup options available to the user
      */
     List<EnrichedLookupOption> getAllFeatures();
 
+    /**
+     * Checks a set of core versions to see if they have been installed
+     * 
+     * @return true if the core modules have been installed
+     */
+    boolean hasCoreModules();
+
+    /**
+     * installs the default modules (such as KJV, ESV, Strongs, Robinson)
+     */
+    void installDefaultModules();
+
+    /**
+     * installs separate modules
+     * 
+     * @param reference the reference, initials or book name
+     */
+    void installModules(String reference);
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -7,6 +7,12 @@
 
 import com.tyndalehouse.step.core.models.LookupOption;
 
+/**
+ * The service providing access to JSword. All JSword calls should preferably be placed in this service
+ * 
+ * @author Chris
+ * 
+ */
 public interface JSwordService {
     /**
      * returns the Osis Text as a String
@@ -31,10 +37,10 @@
     /**
      * looks up any installed module
      * 
-     * @param bibleCategory the category of the bible to lookup
+     * @param bibleCategory the categories of the modules to be returned
      * @return a list of bible books
      */
-    List<Book> getModules(BookCategory bibleCategory);
+    List<Book> getInstalledModules(BookCategory... bibleCategory);
 
     /**
      * Gets the features for a module
@@ -44,4 +50,35 @@
      */
     List<LookupOption> getFeatures(String version);
 
+    /**
+     * Using module initials, checks whether the module has been installed
+     * 
+     * @param moduleInitials the initials of the modules to check for installation state
+     * @return true if the module is installed
+     */
+    boolean isInstalled(String moduleInitials);
+
+    /**
+     * Kicks of a process to install this version (asynchronous)
+     * 
+     * @param version version to be installs
+     */
+    void installBook(String version);
+
+    /**
+     * assesses the progress made on an installation
+     * 
+     * @param bookName the book name
+     * @return the percentage of completion (0 - 1.0)
+     */
+    double getProgressOnInstallation(String bookName);
+
+    /**
+     * retrieves all modules that have been installed
+     * 
+     * @param bookCategory the list of categories to be included
+     * @return all modules whether installed or not
+     */
+    List<Book> getAllModules(BookCategory... bookCategory);
+
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/ModuleService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/ModuleService.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/ModuleService.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -2,6 +2,7 @@
 
 import java.util.List;
 
+import com.tyndalehouse.step.core.models.BibleVersion;
 import com.tyndalehouse.step.core.models.Definition;
 
 /**
@@ -27,4 +28,14 @@
      * @return the definitions associated with the references
      */
     Definition getDefinition(String reference);
+
+    /**
+     * @return all installed modules
+     */
+    List<BibleVersion> getAvailableModules();
+
+    /**
+     * @return a list of all modules that could be installed
+     */
+    List<BibleVersion> getAllInstallableModules();
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -2,18 +2,19 @@
 
 import static com.tyndalehouse.step.core.models.LookupOption.INTERLINEAR;
 import static com.tyndalehouse.step.core.models.LookupOption.STRONG_NUMBERS;
+import static com.tyndalehouse.step.core.utils.JSwordUtils.getSortedSerialisableList;
 import static org.apache.commons.lang.StringUtils.isNotBlank;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import org.crosswire.jsword.book.Book;
 import org.crosswire.jsword.book.BookCategory;
-import org.crosswire.jsword.book.FeatureType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 import com.tyndalehouse.step.core.models.BibleVersion;
 import com.tyndalehouse.step.core.models.EnrichedLookupOption;
 import com.tyndalehouse.step.core.models.LookupOption;
@@ -25,37 +26,38 @@
  * 
  * @author CJBurrell
  */
+ at Singleton
 public class BibleInformationServiceImpl implements BibleInformationService {
-    private final Logger logger = LoggerFactory.getLogger(getClass());
+    private static final Logger LOGGER = LoggerFactory.getLogger(BibleInformationServiceImpl.class);
+    private final List<String> defaultVersions;
+    private final JSwordService jsword;
 
-    @Autowired
-    private JSwordService jsword;
+    /**
+     * The bible information service, retrieving content and meta data
+     * 
+     * @param defaultVersions a list of the default versions that should be installed
+     * @param jsword the jsword service
+     */
+    @Inject
+    public BibleInformationServiceImpl(@Named("defaultVersions") final List<String> defaultVersions,
+            final JSwordService jsword) {
+        this.jsword = jsword;
+        this.defaultVersions = defaultVersions;
+    }
 
-    public List<BibleVersion> getBibleVersions() {
-        this.logger.info("Getting bible versions");
-        final List<Book> bibles = this.jsword.getModules(BookCategory.BIBLE);
-
-        final List<BibleVersion> versions = new ArrayList<BibleVersion>();
-
-        // we only send back what we need
-        for (final Book b : bibles) {
-            final BibleVersion v = new BibleVersion();
-            v.setName(b.getName());
-            v.setInitials(b.getInitials());
-            v.setLanguage(b.getLanguage().getName());
-            v.setHasStrongs(b.hasFeature(FeatureType.STRONGS_NUMBERS));
-            versions.add(v);
-        }
-
-        this.logger.debug("Returning {} versions", bibles.size());
-        return versions;
+    @Override
+    public List<BibleVersion> getAvailableBibleVersions() {
+        LOGGER.info("Getting bible versions");
+        return getSortedSerialisableList(this.jsword.getInstalledModules(BookCategory.BIBLE));
     }
 
+    @Override
     public String getPassageText(final String version, final String reference, final List<LookupOption> options,
             final String interlinearVersion) {
         return this.jsword.getOsisText(version, reference, options, interlinearVersion);
     }
 
+    @Override
     public List<EnrichedLookupOption> getAllFeatures() {
         final LookupOption[] lo = LookupOption.values();
         final List<EnrichedLookupOption> elo = new ArrayList<EnrichedLookupOption>(lo.length + 1);
@@ -70,6 +72,7 @@
         return elo;
     }
 
+    @Override
     public List<LookupOption> getFeaturesForVersion(final String version) {
         final List<LookupOption> features = this.jsword.getFeatures(version);
         if (features.contains(STRONG_NUMBERS)) {
@@ -77,4 +80,27 @@
         }
         return features;
     }
+
+    @Override
+    public boolean hasCoreModules() {
+        for (final String version : this.defaultVersions) {
+            if (!this.jsword.isInstalled(version)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void installDefaultModules() {
+        // we install the module for every core module in the list
+        for (final String book : this.defaultVersions) {
+            this.jsword.installBook(book);
+        }
+    }
+
+    @Override
+    public void installModules(final String reference) {
+        this.jsword.installBook(reference);
+    }
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,6 +1,7 @@
 package com.tyndalehouse.step.core.service.impl;
 
 import static com.tyndalehouse.step.core.xsl.XslConversionType.DEFAULT;
+import static org.apache.commons.lang.StringUtils.isBlank;
 import static org.apache.commons.lang.StringUtils.isNotBlank;
 import static org.apache.commons.lang.StringUtils.isNotEmpty;
 import static org.crosswire.jsword.book.BookCategory.BIBLE;
@@ -13,6 +14,8 @@
 
 import javax.xml.transform.TransformerException;
 
+import org.crosswire.common.progress.JobManager;
+import org.crosswire.common.progress.Progress;
 import org.crosswire.common.xml.Converter;
 import org.crosswire.common.xml.SAXEventProvider;
 import org.crosswire.common.xml.TransformingSAXEventProvider;
@@ -24,11 +27,15 @@
 import org.crosswire.jsword.book.BookFilter;
 import org.crosswire.jsword.book.Books;
 import org.crosswire.jsword.book.FeatureType;
+import org.crosswire.jsword.book.install.InstallException;
+import org.crosswire.jsword.book.install.Installer;
 import org.crosswire.jsword.passage.NoSuchKeyException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.SAXException;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import com.tyndalehouse.step.core.exceptions.StepInternalException;
 import com.tyndalehouse.step.core.models.LookupOption;
 import com.tyndalehouse.step.core.service.JSwordService;
@@ -40,32 +47,75 @@
  * @author CJBurrell
  * 
  */
+ at Singleton
 public class JSwordServiceImpl implements JSwordService {
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+    private static final Logger LOGGER = LoggerFactory.getLogger(JSwordServiceImpl.class);
+    private final List<Installer> bookInstallers;
 
+    /**
+     * constructs the jsword service.
+     * 
+     * @param installers the installers are the objects that query the crosswire servers
+     */
+    @Inject
+    public JSwordServiceImpl(final List<Installer> installers) {
+        this.bookInstallers = installers;
+    }
+
+    /**
+     * @param bibleCategory the categories of books that should be considered
+     * @return returns a list of installed modules
+     */
     @SuppressWarnings("unchecked")
-    public List<Book> getModules(final BookCategory bibleCategory) {
-        if (bibleCategory == null) {
+    public List<Book> getInstalledModules(final BookCategory... bibleCategory) {
+        if (bibleCategory == null || bibleCategory.length == 0) {
             return new ArrayList<Book>();
         }
 
+        // quickly transform the categories to a set for fast comparison
+        final Set<BookCategory> categories = new HashSet<BookCategory>();
+        for (int ii = 0; ii < bibleCategory.length; ii++) {
+            categories.add(bibleCategory[ii]);
+        }
+
         // we set up a filter to retrieve just certain types of books
         final BookFilter bf = new BookFilter() {
             public boolean test(final Book b) {
-                return bibleCategory.equals(b.getBookCategory());
+                return categories.contains(b.getBookCategory());
             }
         };
         return Books.installed().getBooks(bf);
     }
 
+    /**
+     * @param bibleCategory the list of books that should be considered
+     * @return a list of all modules
+     */
+    @SuppressWarnings("unchecked")
+    public List<Book> getAllModules(final BookCategory... bibleCategory) {
+        final List<Book> books = new ArrayList<Book>();
+        for (final Installer installer : this.bookInstallers) {
+            try {
+                installer.reloadBookList();
+                books.addAll(installer.getBooks());
+            } catch (final InstallException e) {
+                // log an error
+                LOGGER.error("Unable to update installer", e);
+            }
+        }
+        return books;
+    }
+
+    @Override
     public String getOsisText(final String version, final String reference) {
         final List<LookupOption> options = new ArrayList<LookupOption>();
         return getOsisText(version, reference, options, null);
     }
 
+    @Override
     public String getOsisText(final String version, final String reference, final List<LookupOption> options,
             final String interlinearVersion) {
-        this.logger.debug("Retrieving text for ({}, {})", version, reference);
+        LOGGER.debug("Retrieving text for ({}, {})", version, reference);
 
         try {
             final Book currentBook = Books.installed().getBook(version);
@@ -81,13 +131,12 @@
                         // for now, we just assume that we'll only have one option, but this may change later
                         // TODO, we can probably cache the resource
                         final TransformingSAXEventProvider tsep = new TransformingSAXEventProvider(getClass()
-                                .getResource(requiredTransformation.iterator().next().getFile()).toURI(), osissep);
+                                .getResource(requiredTransformation.iterator().next().getFile()).toURI(),
+                                osissep);
 
                         // set parameters here
                         setOptions(tsep, options, version, reference);
                         setupInterlinearOptions(tsep, interlinearVersion, reference);
-
-                        // then return
                         return tsep;
                     } catch (final URISyntaxException e) {
                         throw new StepInternalException("Failed to load resource correctly", e);
@@ -97,10 +146,10 @@
             }.convert(osissep);
             return XMLUtil.writeToString(htmlsep);
         } catch (final NoSuchKeyException e) {
-            throw new StepInternalException("The verse specified was not found: [" + reference + "]", e);
+            throw new StepInternalException("The verse specified was not found: " + reference, e);
         } catch (final BookException e) {
-            throw new StepInternalException("Unable to query the book data to retrieve specified passage [" + version
-                    + "] [" + reference + "]", e);
+            throw new StepInternalException("Unable to query the book data to retrieve specified passage: "
+                    + version + ", " + reference, e);
         } catch (final SAXException e) {
             throw new StepInternalException(e.getMessage(), e);
         } catch (final TransformerException e) {
@@ -131,6 +180,7 @@
         return chosenOptions;
     }
 
+    @Override
     public List<LookupOption> getFeatures(final String version) {
         // obtain the book
         final Book book = Books.installed().getBook(version);
@@ -144,26 +194,29 @@
         // cycle through each option
         for (final LookupOption lo : LookupOption.values()) {
             final FeatureType ft = FeatureType.fromString(lo.getXsltParameterName());
-            if (ft != null && isNotEmpty(lo.getDisplayName())) {
-                if (book.getBookMetaData().hasFeature(ft)) {
-                    options.add(lo);
-                }
+            if (ft != null && isNotEmpty(lo.getDisplayName()) && book.getBookMetaData().hasFeature(ft)) {
+                options.add(lo);
             }
         }
         return options;
     }
 
-    private void setupInterlinearOptions(final TransformingSAXEventProvider tsep, final String interlinearVersion,
-            final String reference) {
+    /**
+     * sets up the default interlinear options
+     * 
+     * @param tsep the transformer that we want to set up
+     * @param interlinearVersion the interlinear version(s) that the users have requested
+     * @param reference the reference the user is interested in
+     */
+    private void setupInterlinearOptions(final TransformingSAXEventProvider tsep,
+            final String interlinearVersion, final String reference) {
         if (tsep.getParameter(LookupOption.INTERLINEAR.getXsltParameterName()) != null) {
             tsep.setParameter("interlinearReference", reference);
 
             if (isNotBlank(interlinearVersion)) {
                 tsep.setParameter("interlinearVersion", interlinearVersion);
-            } else {
-                // depending on OT or NT, we select a default interlinear version
-
             }
+            // TODO else depending on OT or NT, we select a default interlinear version
         }
     }
 
@@ -174,7 +227,6 @@
      * @param options the options available
      * @param version the version to initialise a potential interlinear with
      * @param textScope the scope of the text to lookup
-     * @return the XSLT that will give me the correct transformation
      */
     protected void setOptions(final TransformingSAXEventProvider tsep, final List<LookupOption> options,
             final String version, final String textScope) {
@@ -187,4 +239,81 @@
         }
     }
 
+    @Override
+    public boolean isInstalled(final String moduleInitials) {
+        return Books.installed().getBook(moduleInitials) != null;
+    }
+
+    @Override
+    public void installBook(final String initials) {
+        LOGGER.debug("Installing module [{}]", initials);
+
+        if (isBlank(initials)) {
+            throw new StepInternalException("No version was found");
+        }
+
+        // check if already installed?
+        if (!isInstalled(initials)) {
+            LOGGER.debug("Book was not already installed, so kicking off installation process [{}]");
+            for (final Installer i : this.bookInstallers) {
+                final Book bookToBeInstalled = i.getBook(initials);
+
+                if (bookToBeInstalled != null) {
+                    // then we can kick off installation and return
+                    try {
+                        i.install(bookToBeInstalled);
+                    } catch (final InstallException e) {
+                        // we log error here,
+                        LOGGER.error(
+                                "An error occurred error, and we unable to use this installer for module"
+                                        + initials, e);
+
+                        // but go round the loop to see if more options are available
+                        continue;
+                    }
+                    return;
+                }
+            }
+            // if we get here, then we were unable to install the book
+            // since we couldn't find it.
+            throw new StepInternalException("Unable to find book with initials " + initials);
+        }
+
+        // if we get here then we had already installed the book - how come we're asking for this again?
+        LOGGER.warn("A request to install an already installed book was made for initials " + initials);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public double getProgressOnInstallation(final String bookName) {
+        if (isBlank(bookName)) {
+            throw new StepInternalException("The book name provided was blank");
+        }
+
+        if (isInstalled(bookName)) {
+            return 1;
+        }
+
+        final Set<Progress> jswordJobs = JobManager.getJobs();
+        // not yet installed (or at least wasn't on the lines above, so check job list
+        for (final Progress p : jswordJobs) {
+            final String expectedJobName = "Installing book: " + bookName;
+            if (expectedJobName.equals(p.getJobName())) {
+                if (p.isFinished()) {
+                    return 1;
+                }
+
+                return (double) p.getWork() / p.getTotalWork();
+            }
+        }
+
+        // the job may have completed by now, while we did the search, so do a final check
+        if (isInstalled(bookName)) {
+            return 1;
+        }
+
+        throw new StepInternalException(
+                "An unknown error has occurred: the job has disappeared of the job list, "
+                        + "but the module is not installed");
+    }
 }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImpl.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImpl.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,5 +1,7 @@
 package com.tyndalehouse.step.core.service.impl;
 
+import static com.tyndalehouse.step.core.utils.JSwordUtils.getSortedSerialisableList;
+import static org.apache.commons.collections.CollectionUtils.subtract;
 import static org.apache.commons.lang.StringUtils.split;
 
 import java.util.ArrayList;
@@ -7,11 +9,16 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookCategory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
 import com.tyndalehouse.step.core.exceptions.StepInternalException;
+import com.tyndalehouse.step.core.models.BibleVersion;
 import com.tyndalehouse.step.core.models.Definition;
 import com.tyndalehouse.step.core.service.JSwordService;
 import com.tyndalehouse.step.core.service.ModuleService;
@@ -23,13 +30,26 @@
  * @author Chris Burrell
  * 
  */
+ at Singleton
 public class ModuleServiceImpl implements ModuleService {
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-    private Map<String, String> defaultModuleLexicons;
+    private static final Logger LOGGER = LoggerFactory.getLogger(ModuleServiceImpl.class);
+    private final Map<String, String> defaultLexiconsRefs;
+    private final JSwordService jsword;
 
-    @Autowired
-    private JSwordService jsword;
+    /**
+     * constructs a service to give module information and content
+     * 
+     * @param lexiconRefs the default references that should be used
+     * @param jsword the jsword service to retrieve data
+     */
+    @Inject
+    public ModuleServiceImpl(@Named("defaultLexiconRefs") final Map<String, String> lexiconRefs,
+            final JSwordService jsword) {
+        this.defaultLexiconsRefs = lexiconRefs;
+        this.jsword = jsword;
+    }
 
+    @Override
     public Definition getDefinition(final String reference) {
         final String lookupModule = getLookupModule(reference);
         if (lookupModule != null) {
@@ -37,10 +57,11 @@
                     StringConversionUtils.getAnyKey(reference, false)));
         }
 
-        this.logger.warn("No module could be found for [{}]", reference);
+        LOGGER.warn("No module could be found for [{}]", reference);
         return null;
     }
 
+    @Override
     public List<Definition> getDefinitions(final String references) {
         // first we split the definitions in separate parts
         final String[] refs = split(references);
@@ -51,7 +72,7 @@
 
         final List<Definition> defs = new ArrayList<Definition>();
         for (final String r : refs) {
-            this.logger.debug("Looking up {}", r);
+            LOGGER.debug("Looking up {}", r);
             final Definition definition = getDefinition(r);
             if (definition != null) {
                 defs.add(definition);
@@ -62,14 +83,13 @@
     }
 
     /**
-     * TODO: later we can drive this with a dropdown on the UI Based on the reference provided, we determine the correct
-     * module to lookup
+     * Returns the module that should be used to lookup a reference
      * 
      * @param reference the reference to base the lookup option on
      * @return the initials of the module to lookup
      */
     String getLookupModule(final String reference) {
-        for (final Entry<String, String> e : this.defaultModuleLexicons.entrySet()) {
+        for (final Entry<String, String> e : this.defaultLexiconsRefs.entrySet()) {
             if (reference.startsWith(e.getKey())) {
                 return e.getValue();
             }
@@ -77,11 +97,21 @@
         return null;
     }
 
-    /**
-     * @param defaultModuleLexicons the defaultModuleLexicons to set
-     */
-    public void setDefaultModuleLexicons(final Map<String, String> defaultModuleLexicons) {
-        this.defaultModuleLexicons = defaultModuleLexicons;
+    @Override
+    public List<BibleVersion> getAvailableModules() {
+        LOGGER.info("Getting bible versions");
+        return getSortedSerialisableList(this.jsword.getInstalledModules(BookCategory.BIBLE, BookCategory.DICTIONARY,
+                BookCategory.COMMENTARY));
     }
 
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<BibleVersion> getAllInstallableModules() {
+        LOGGER.info("Returning all modules currently not installed");
+        final List<BibleVersion> installedVersions = getAvailableModules();
+        final List<Book> allModules = this.jsword.getAllModules(BookCategory.BIBLE, BookCategory.DICTIONARY,
+                BookCategory.COMMENTARY);
+
+        return getSortedSerialisableList(subtract(allModules, installedVersions));
+    }
 }

Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/JSwordUtils.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/JSwordUtils.java	                        (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/JSwordUtils.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,63 @@
+package com.tyndalehouse.step.core.utils;
+
+import static java.util.Collections.sort;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+import org.crosswire.common.util.Language;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.FeatureType;
+
+import com.tyndalehouse.step.core.models.BibleVersion;
+
+/**
+ * a set of utility methods to manipulate the JSword objects coming out
+ * 
+ * @author Chris
+ * 
+ */
+public final class JSwordUtils {
+    /**
+     * hiding implementaiton
+     */
+    private JSwordUtils() {
+        // no implementation
+    }
+
+    /**
+     * returns a sorted list from another list, with only the required information
+     * 
+     * @param bibles a list of jsword bibles
+     * @return the list of bibles
+     */
+    public static List<BibleVersion> getSortedSerialisableList(final Collection<Book> bibles) {
+        final List<BibleVersion> versions = new ArrayList<BibleVersion>();
+
+        // we only send back what we need
+        for (final Book b : bibles) {
+            final BibleVersion v = new BibleVersion();
+            v.setName(b.getName());
+            v.setInitials(b.getInitials());
+
+            final Language language = b.getLanguage();
+            if (language != null) {
+
+                v.setLanguage(language.getName());
+            }
+            v.setHasStrongs(b.hasFeature(FeatureType.STRONGS_NUMBERS));
+            versions.add(v);
+        }
+
+        // finally sort by initials
+        sort(versions, new Comparator<BibleVersion>() {
+            public int compare(final BibleVersion o1, final BibleVersion o2) {
+                return o1.getInitials().compareTo(o2.getInitials());
+            }
+        });
+
+        return versions;
+    }
+}

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/XslHelper.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/XslHelper.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/utils/XslHelper.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -4,9 +4,15 @@
 import static java.lang.String.format;
 import static org.apache.commons.lang.StringUtils.split;
 
+/**
+ * A helper class for use during XSL transformations
+ * 
+ * @author Chris
+ * 
+ */
 public final class XslHelper {
-    private static final int APPROXIMATE_ANCHOR_LENGTH = 56;
-    private static final int APPROXIMATE_SPAN_LENGTH = 46;
+    private static final int APPROX_ANCHOR_LENGTH = 56;
+    private static final int APPROX_SPAN_LENGTH = 46;
     private static final String START_ANCHOR = "<a href=\"";
     private static final String START_FUNCTION_WRAPPER = "('";
     private static final String END_FUNCTION_WRAPPER = "', this)";
@@ -26,7 +32,9 @@
      * returns a "span" element for use in an HTML document
      * 
      * @param strongsText the key straight from the OSIS text
+     * @param functionCall the javascript function that will be called upon click of the word
      * @return a span containing all the strongs, seperated by spaces
+     * 
      */
     public static String getSpanFromAttributeName(final String strongsText, final String functionCall) {
         final String[] strongs = split(strongsText, SEPARATORS);
@@ -35,7 +43,7 @@
         }
 
         // we transform each strong to something like: "<a href=\"%s\">%s</a>";
-        final StringBuilder sb = new StringBuilder(APPROXIMATE_SPAN_LENGTH + strongs.length * APPROXIMATE_ANCHOR_LENGTH);
+        final StringBuilder sb = new StringBuilder(APPROX_SPAN_LENGTH + strongs.length * APPROX_ANCHOR_LENGTH);
 
         String strongKey;
         for (int ii = 0; ii < strongs.length; ii++) {

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,5 +1,12 @@
 package com.tyndalehouse.step.core.xsl;
 
+/**
+ * An individual interlinear provider that cross-references text passed in using verse, strong, and morphology
+ * information
+ * 
+ * @author Chris
+ * 
+ */
 public interface InterlinearProvider {
     /**
      * This is the more specific method

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/MultiInterlinearProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/MultiInterlinearProvider.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/MultiInterlinearProvider.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,5 +1,11 @@
 package com.tyndalehouse.step.core.xsl;
 
+/**
+ * the Interface that a Mutli interlinear provider shall abide to
+ * 
+ * @author Chris
+ * 
+ */
 public interface MultiInterlinearProvider {
     /**
      * This is the more specific method

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -21,14 +21,25 @@
      */
     private final String file;
 
+    /**
+     * giving a default XSL file to this Conversion type
+     */
     private XslConversionType() {
         this("default.xsl");
     }
 
+    /**
+     * constructing a type associated with a specific file
+     * 
+     * @param file the XSL transformation file
+     */
     private XslConversionType(final String file) {
         this.file = file;
     }
 
+    /**
+     * @return the file associated with this type
+     */
     public String getFile() {
         return this.file;
     }

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -6,6 +6,8 @@
  * A Strong Morph Map takes two keys, and gives one word back. The following DualKey relies on hashCode. The hash
  * function relies on toString so T and S need to have fast toString().
  * 
+ * @param <T> the first part of the key
+ * @param <S> the second part of the key
  * @author Chris
  * 
  */
@@ -13,6 +15,12 @@
     private final T t;
     private final S s;
 
+    /**
+     * creates a composite key
+     * 
+     * @param t the first part of the key
+     * @param s the second part of the key
+     */
     public DualKey(final T t, final S s) {
         this.t = t;
         this.s = s;
@@ -35,7 +43,7 @@
     @Override
     public int hashCode() {
         // we need to return the same hashcode based on s and t
-        return (this.t.toString().concat(this.s.toString())).hashCode();
+        return this.t.toString().concat(this.s.toString()).hashCode();
     }
 
     @Override

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -2,6 +2,8 @@
 
 import static com.tyndalehouse.step.core.utils.StringConversionUtils.getAnyKey;
 import static com.tyndalehouse.step.core.utils.StringConversionUtils.getStrongKey;
+import static java.lang.String.format;
+import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
 import static org.apache.commons.lang.StringUtils.isBlank;
 import static org.apache.commons.lang.StringUtils.isNotBlank;
 import static org.apache.commons.lang.StringUtils.split;
@@ -31,9 +33,9 @@
 import com.tyndalehouse.step.core.xsl.InterlinearProvider;
 
 /**
- * This object is not purposed to be used as a singleton. It builds up textual information on initialisation, and is
- * specific to requests. On initialisation, the OSIS XML is retrieved and iterated through to find all strong/morph
- * candidates
+ * This object is not purposed to be used as a singleton. It builds up textual information on initialisation,
+ * and is specific to requests. On initialisation, the OSIS XML is retrieved and iterated through to find all
+ * strong/morph candidates
  * 
  * @author Chris
  * 
@@ -51,8 +53,8 @@
     private final Map<DualKey<String, String>, List<String>> limitedAccuracy = new HashMap<DualKey<String, String>, List<String>>();
 
     /**
-     * finally, this is just a list of all the strongs and their mappings. Still would be fairly good as long as the
-     * same word isn't used multiple times.
+     * finally, this is just a list of all the strongs and their mappings. Still would be fairly good as long
+     * as the same word isn't used multiple times.
      */
     private final Map<String, String> worstAccuracy = new HashMap<String, String>();
 
@@ -69,6 +71,10 @@
         }
 
         final Book currentBook = Books.installed().getBook(version);
+        if (currentBook == null) {
+            throw new StepInternalException(format("Couldn't look up book: [%s]", version));
+        }
+
         BookData bookData;
 
         try {
@@ -88,12 +94,14 @@
         // exposing package private constructor
     }
 
+    @Override
     public String getWord(final String verseNumber, final String strong, final String morph) {
         // we use a linked hashset, because we want the behaviour of a set while we add to it,
         // but at the end, we will want to return the elements in order
         final Set<String> results = new LinkedHashSet<String>();
         if (isBlank(strong)) {
             // we might as well return, as we have no information to go on
+            return "";
         }
 
         // the keys passed in may have multiple references and morphologies, therefore, we need to lookup
@@ -106,7 +114,8 @@
             boolean foundMatchForStrong = false;
             final String strongKey = getAnyKey(s);
 
-            // each could be using the morphs we have, so try them all - this gets skipped if we have no morphs
+            // each could be using the morphs we have, so try them all - this gets skipped if we have no
+            // morphs
             for (final String m : morphs) {
                 // lookup (strong,morph) -> word first
                 final DualKey<String, String> key = new DualKey<String, String>(getStrongKey(strongKey), m);
@@ -162,7 +171,7 @@
             final DualKey<String, String> key = new DualKey<String, String>(strong, verseNumber);
 
             final List<String> list = this.limitedAccuracy.get(key);
-            if (list != null && list.size() != 0) {
+            if (isNotEmpty(list)) {
                 return list.get(0);
             }
         }
@@ -256,14 +265,14 @@
     /**
      * Finally, we have some information to add to this provider. We try and add it in an efficient fashion.
      * 
-     * So, how do we store this? The most meaningful piece of data is a STRONG number, since it identifies the word that
-     * we want to retrieve. Without the strong number, we don't have any information at all. Therefore, the first level
-     * of lookup should be by Strong number.
+     * So, how do we store this? The most meaningful piece of data is a STRONG number, since it identifies the
+     * word that we want to retrieve. Without the strong number, we don't have any information at all.
+     * Therefore, the first level of lookup should be by Strong number.
      * 
      * Morphology-wise, each word might have a small number of options, so a linked list will do for this
      * 
-     * One would think that strong -> morph -> word will be unique. In the case of having just strong, we should use
-     * verse locality to maximise our chance of getting the right word (strong -> verse -> word)
+     * One would think that strong -> morph -> word will be unique. In the case of having just strong, we
+     * should use verse locality to maximise our chance of getting the right word (strong -> verse -> word)
      * 
      * So in summary, we use: strong -> morph -> word strong -> verse -> list(word) (not unique)
      * 
@@ -272,7 +281,8 @@
      * @param morph the morphology (identifies how the used is word in the sentence - i.e. grammar)
      * @param word the word to be stored
      */
-    void addTextualInfo(final String verseReference, final String strong, final String morph, final String word) {
+    void addTextualInfo(final String verseReference, final String strong, final String morph,
+            final String word) {
         final String strongKey = getAnyKey(strong);
 
         if (isNotBlank(strongKey) && isNotBlank(morph)) {

Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/MultiInterlinearProviderImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/MultiInterlinearProviderImpl.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/MultiInterlinearProviderImpl.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -18,13 +18,14 @@
 public class MultiInterlinearProviderImpl implements MultiInterlinearProvider {
     /** we separate by commas and spaces */
     private static final String VERSION_SEPARATOR = ", ";
-    Map<String, InterlinearProvider> interlinearProviders = new HashMap<String, InterlinearProvider>();
+    private final Map<String, InterlinearProvider> interlinearProviders = new HashMap<String, InterlinearProvider>();
 
     /**
      * sets up the interlinear provider with the correct version and text scope.
      * 
-     * @param version the version to use to set up the interlinear
-     * @param textScope the text scope reference, defining the bounds of the lookup
+     * @param versions the versions to use to set up the interlinear
+     * @param textScope the reference, or passage range that should be considered when setting up the
+     *            interlinear provider
      */
     public MultiInterlinearProviderImpl(final String versions, final String textScope) {
         // first check whether the values passed in are correct
@@ -40,7 +41,9 @@
         }
     }
 
-    public String getWord(final String version, final String verseNumber, final String strong, final String morph) {
+    @Override
+    public String getWord(final String version, final String verseNumber, final String strong,
+            final String morph) {
         return this.interlinearProviders.get(version).getWord(verseNumber, strong, morph);
     }
 }

Deleted: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_default.xsl
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_default.xsl	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_default.xsl	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,1349 +0,0 @@
-<?xml version="1.0"?>
-<!--
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. This program is distributed in the hope
- * that it will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- *       http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- *      Free Software Foundation, Inc.
- *      59 Temple Place - Suite 330
- *      Boston, MA 02111-1307, USA
- *
- * Copyright: 2005
- *     The copyright to this program is held by it's authors.
- *
- * ID: $Id: default.xsl 1943 2009-03-25 11:43:28Z dmsmith $
- -->
- <!--
- * Transforms OSIS to HTML for viewing within JSword browsers.
- * Note: There are custom protocols which the browser must handle.
- * 
- * @see gnu.lgpl.License for license details.
- *      The copyright to this program is held by it's authors.
- * @author Joe Walker [joe at eireneh dot com]
- * @author DM Smith [dmsmith555 at yahoo dot com]
- * @author Chris Burrell [chris at burrell dot me dot uk] 
- -->
- <xsl:stylesheet
-  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-  version="1.0"
-  xmlns:jsword="http://xml.apache.org/xalan/java"
-  extension-element-prefixes="jsword">
-
-  <!--  Version 3.0 is necessary to get br to work correctly. -->
-  <xsl:output method="html" version="3.0" omit-xml-declaration="yes" indent="no"/>
-
-  <!-- Be very careful about introducing whitespace into the document.
-       strip-space merely remove space between one tag and another tag.
-       This may cause significant whitespace to be removed.
-       
-       It is easy to have apply-templates on a line to itself which if
-       it encounters text before anything else will introduce whitespace.
-       With the browser we are using, span will introduce whitespace
-       but font does not. Therefore we use font as a span.
-    -->
-  <!-- gdef and hdef refer to hebrew and greek definitions keyed by strongs -->
-  <!-- The absolute base for relative references. -->
-  <xsl:param name="greek.def.protocol" select="'gdef:'"/>
-  <xsl:param name="hebrew.def.protocol" select="'hdef:'"/>
-  <xsl:param name="lex.def.protocol" select="'lex:'"/>
-  <!-- currently these are not used, but they are for morphologic forms -->
-  <xsl:param name="greek.morph.protocol" select="'gmorph:'"/>
-  <xsl:param name="hebrew.morph.protocol" select="'hmorph:'"/>
-
-  <!-- The absolute base for relative references. -->
-  <xsl:param name="baseURL" select="''"/>
-
-  <!-- Whether to show Strongs or not -->
-  <xsl:param name="StrongsNumbers" select="'false'"/>
-
-  <!-- Whether to show morphologic forms or not -->
-  <xsl:param name="Morph" select="'false'"/>
-
-  <!-- Whether to start each verse on an new line or not -->
-  <xsl:param name="VLine" select="'false'"/>
-
-  <!-- Whether to show non-canonical "headings" or not -->
-  <xsl:param name="Headings" select="'false'"/>
-
-  <!-- Whether to show notes or not -->
-  <xsl:param name="Notes" select="'false'"/>
-
-  <!-- Whether to have linking cross references or not -->
-  <xsl:param name="XRef" select="'false'"/>
-
-  <!-- Whether to output Verse numbers or not -->
-  <xsl:param name="VNum" select="'false'"/>
-
-  <!-- Whether to output Chapter and Verse numbers or not -->
-  <xsl:param name="CVNum" select="'false'"/>
-
-  <!-- Whether to output Book, Chapter and Verse numbers or not -->
-  <xsl:param name="BCVNum" select="'false'"/>
-
-  <!-- Whether to output superscript verse numbers or normal size ones -->
-  <xsl:param name="TinyVNum" select="'false'"/>
-
-  <!-- The order of display. Hebrew is rtl (right to left) -->
-  <xsl:param name="direction" select="'ltr'"/>
-
-  <!-- Create a global key factory from which OSIS ids will be generated -->
-  <xsl:variable name="keyf" select="jsword:org.crosswire.jsword.passage.PassageKeyFactory.instance()"/>
-  <!-- Create a global number shaper that can transform 0-9 into other number systems. -->
-  <xsl:variable name="shaper" select="jsword:org.crosswire.common.icu.NumberShaper.new()"/>
-
-  <!--=======================================================================-->
-  <xsl:template match="/">
-      <div>
-        <!-- If there are notes, output a table with notes in the 2nd column. -->
-        <!-- There is a rendering bug which prevents the notes from adhering to the right edge. -->
-        <xsl:choose>
-          <xsl:when test="$Notes = 'true' and //note[not(@type = 'x-strongsMarkup')]">
-            <xsl:choose>
-              <xsl:when test="$direction != 'rtl'">
-                <table cols="2" cellpadding="5" cellspacing="5">
-                  <tr>
-                    <!-- The two rows are swapped until the bug is fixed. -->
-                    <td valign="top" class="notes">
-                      <p>&#160;</p>
-                      <xsl:apply-templates select="//verse" mode="print-notes"/>
-                    </td>
-                    <td valign="top" class="text">
-                      <xsl:apply-templates/>
-                    </td>
-                  </tr>
-                </table>
-              </xsl:when>
-              <xsl:otherwise>
-                <!-- reverse the table for Right to Left languages -->
-                <table cols="2" cellpadding="5" cellspacing="5">
-                  <!-- In a right to left, the alignment should be reversed too -->
-                  <tr align="right">
-                    <td valign="top" class="notes">
-                      <p>&#160;</p>
-                      <xsl:apply-templates select="//note" mode="print-notes"/>
-                    </td>
-                    <td valign="top" class="text">
-                      <xsl:apply-templates/>
-                    </td>
-                  </tr>
-                </table>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:apply-templates/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </div>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!--
-    == A proper OSIS document has osis as its root.
-    == We dig deeper for its content.
-    -->
-  <xsl:template match="osis">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!--
-    == An OSIS document may contain more that one work.
-    == Each work is held in an osisCorpus element.
-    == If there is only one work, then this element will (should) be absent.
-    == Process each document in turn.
-    == It might be reasonable to dig into the header element of each work
-    == and get its title.
-    == Otherwise, we ignore the header and work elements and just process
-    == the osisText elements.
-    -->
-  <xsl:template match="osisCorpus">
-    <xsl:apply-templates select="osisText"/>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!--
-    == Each work has an osisText element.
-    == We ignore the header and work elements and process its div elements.
-    == While divs can be milestoned, the osisText element requires container
-    == divs.
-    -->
-  <xsl:template match="osisText">
-    <xsl:apply-templates select="div"/>
-  </xsl:template>
-  
-  <!-- Ignore headers and its elements -->
-  <xsl:template match="header"/>
-  <xsl:template match="revisionDesc"/>
-  <xsl:template match="work"/>
-   <!-- <xsl:template match="title"/> who's parent is work -->
-  <xsl:template match="contributor"/>
-  <xsl:template match="creator"/>
-  <xsl:template match="subject"/>
-  <!-- <xsl:template match="date"/> who's parent is work -->
-  <xsl:template match="description"/>
-  <xsl:template match="publisher"/>
-  <xsl:template match="type"/>
-  <xsl:template match="format"/>
-  <xsl:template match="identifier"/>
-  <xsl:template match="source"/>
-  <xsl:template match="language"/>
-  <xsl:template match="relation"/>
-  <xsl:template match="coverage"/>
-  <xsl:template match="rights"/>
-  <xsl:template match="scope"/>
-  <xsl:template match="workPrefix"/>
-  <xsl:template match="castList"/>
-  <xsl:template match="castGroup"/>
-  <xsl:template match="castItem"/>
-  <xsl:template match="actor"/>
-  <xsl:template match="role"/>
-  <xsl:template match="roleDesc"/>
-  <xsl:template match="teiHeader"/>
-  <xsl:template match="refSystem"/>
-
-
-  <!-- Ignore titlePage -->
-  <xsl:template match="titlePage"/>
-
-  <!--=======================================================================-->
-  <!-- 
-    == Div provides the major containers for a work.
-    == Divs are milestoneable.
-    -->
-  <xsl:template match="div[@type='x-center']">
-    <div align="center">
-      <xsl:apply-templates/>
-    </div>
-  </xsl:template>
-
-  <xsl:template match="div">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="div" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!-- Handle verses as containers and as a start verse.                     -->
-  <xsl:template match="verse[not(@eID)]">
-    <!-- output each preverse element in turn -->
-    <xsl:for-each select=".//*[@subType = 'x-preverse' or @subtype = 'x-preverse']">
-      <xsl:choose>
-        <xsl:when test="local-name() = 'title'">
-          <!-- Always show canonical titles or if headings is turned on -->
-          <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-            <h3 class="heading"><xsl:apply-templates /></h3>
-          </xsl:if>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:apply-templates />
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:for-each>
-    <!-- Handle the KJV paragraph marker. -->
-    <xsl:if test="milestone[@type = 'x-p']"><br/><br/></xsl:if>
-    <!-- If the verse doesn't start on its own line and -->
-    <!-- the verse is not the first verse of a set of siblings, -->
-    <!-- output an extra space. -->
-    <xsl:if test="$VLine = 'false' and preceding-sibling::*[local-name() = 'verse']">
-      <xsl:text>&#160;</xsl:text>
-    </xsl:if>
-    <!-- Always output the verse -->
-    <xsl:choose>
-      <xsl:when test="$VLine = 'true'">
-        <div class="l"><a name="{@osisID}"><xsl:call-template name="versenum"/></a><xsl:apply-templates/></div>
-      </xsl:when>
-      <xsl:otherwise>
-        <span class="verse"><xsl:call-template name="versenum"/><xsl:apply-templates/></span>
-        <!-- Follow the verse with an extra space -->
-        <!-- when they don't start on lines to themselves -->
-        <xsl:text> </xsl:text>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="verse[not(@eID)]" mode="jesus">
-    <!-- If the verse doesn't start on its own line and -->
-    <!-- the verse is not the first verse of a set of siblings, -->
-    <!-- output an extra space. -->
-    <xsl:if test="$VLine = 'false' and preceding-sibling::*[local-name() = 'verse']">
-      <xsl:text>&#160;</xsl:text>
-    </xsl:if>
-    <xsl:variable name="title" select=".//title"/>
-    <xsl:if test="string-length($title) > 0">
-      <h3 class="heading"><xsl:value-of select="$title"/></h3>
-    </xsl:if>
-    <!-- Handle the KJV paragraph marker. -->
-    <xsl:if test="milestone[@type = 'x-p']"><br/><br/></xsl:if>
-    <!-- Always output the verse -->
-    <xsl:choose>
-      <xsl:when test="$VLine = 'true'">
-        <div class="l"><a name="{@osisID}"><xsl:call-template name="versenum"/></a><xsl:apply-templates mode="jesus"/></div>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:call-template name="versenum"/><xsl:apply-templates mode="jesus"/>
-        <!-- Follow the verse with an extra space -->
-        <!-- when they don't start on lines to themselves -->
-        <xsl:text> </xsl:text>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="verse" mode="print-notes">
-    <xsl:if test=".//note[not(@type) or not(@type = 'x-strongsMarkup')]">
-      <xsl:variable name="passage" select="jsword:getValidKey($keyf, @osisID)"/>
-      <a href="#{substring-before(concat(@osisID, ' '), ' ')}">
-        <xsl:value-of select="jsword:getName($passage)"/>
-      </a>
-      <xsl:apply-templates select=".//note" mode="print-notes" />
-      <div><xsl:text>&#160;</xsl:text></div>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template name="versenum">
-    <!-- Are verse numbers wanted? -->
-    <xsl:if test="$VNum = 'true'">
-      <!-- An osisID can be a space separated list of them -->
-      <xsl:variable name="firstOsisID" select="substring-before(concat(@osisID, ' '), ' ')"/>
-      <xsl:variable name="book" select="substring-before($firstOsisID, '.')"/>
-      <xsl:variable name="chapter" select="jsword:shape($shaper, substring-before(substring-after($firstOsisID, '.'), '.'))"/>
-      <!-- If n is present use it for the number -->
-      <xsl:variable name="verse">
-        <xsl:choose>
-          <xsl:when test="@n">
-            <xsl:value-of select="jsword:shape($shaper, string(@n))"/>
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:value-of select="jsword:shape($shaper, substring-after(substring-after($firstOsisID, '.'), '.'))"/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </xsl:variable>
-      <xsl:variable name="versenum">
-        <xsl:choose>
-          <xsl:when test="$BCVNum = 'true'">
-            <xsl:variable name="passage" select="jsword:getValidKey($keyf, @osisID)"/>
-            <xsl:value-of select="jsword:getName($passage)"/>
-          </xsl:when>
-          <xsl:when test="$CVNum = 'true'">
-            <xsl:value-of select="concat($chapter, ' : ', $verse)"/>
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:value-of select="$verse"/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </xsl:variable>
-      <!--
-        == Surround versenum with dup
-        -->
-      <xsl:choose>
-        <xsl:when test="$TinyVNum = 'true' and $Notes = 'true'">
-          <a name="{@osisID}"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></a>
-        </xsl:when>
-        <xsl:when test="$TinyVNum = 'true' and $Notes = 'false'">
-          <span class="verseNumber"><xsl:value-of select="$versenum"/></span>
-        </xsl:when>
-        <xsl:when test="$TinyVNum = 'false' and $Notes = 'true'">
-          <a name="{@osisID}">(<xsl:value-of select="$versenum"/>)</a>
-          <xsl:text> </xsl:text>
-        </xsl:when>
-        <xsl:otherwise>
-          (<xsl:value-of select="$versenum"/>)
-          <xsl:text> </xsl:text>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-    <xsl:if test="$VNum = 'false' and $Notes = 'true'">
-      <a name="{@osisID}"></a>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="a">
-    <a href="{@href}"><xsl:apply-templates/></a>
-  </xsl:template>
-
-  <xsl:template match="a" mode="jesus">
-    <a href="{@href}"><xsl:apply-templates mode="jesus"/></a>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!-- When we encounter a note, we merely output a link to the note. -->
-  <xsl:template match="note[@type = 'x-strongsMarkup']"/>
-  <xsl:template match="note[@type = 'x-strongsMarkup']" mode="jesus"/>
-  <xsl:template match="note[@type = 'x-strongsMarkup']" mode="print-notes"/>
-
-  <xsl:template match="note">
-    <xsl:if test="$Notes = 'true'">
-      <!-- If there is a following sibling that is a note, emit a separator -->
-      <xsl:variable name="siblings" select="../child::node()"/>
-      <xsl:variable name="next-position" select="position() + 1"/>
-      <xsl:choose>
-        <xsl:when test="name($siblings[$next-position]) = 'note'">
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a>, </sup>
-        </xsl:when>
-        <xsl:otherwise>
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a></sup>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template match="note" mode="jesus">
-    <xsl:if test="$Notes = 'true'">
-     <!-- If there is a following sibling that is a note, emit a separator -->
-      <xsl:variable name="siblings" select="../child::node()"/>
-      <xsl:variable name="next-position" select="position() + 1"/>
-      <xsl:choose>
-        <xsl:when test="$siblings[$next-position] and name($siblings[$next-position]) = 'note'">
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a>, </sup>
-        </xsl:when>
-        <xsl:otherwise>
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a></sup>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="note" mode="print-notes">
-    <div class="margin">
-      <strong><xsl:call-template name="generateNoteXref"/></strong>
-      <a name="note-{generate-id(.)}">
-        <xsl:text> </xsl:text>
-      </a>
-      <xsl:apply-templates/>
-    </div>
-  </xsl:template>
-
-  <!--
-    == If the n attribute is present then use that for the cross ref otherwise create a letter.
-    == Note: numbering restarts with each verse.
-    -->
-  <xsl:template name="generateNoteXref">
-    <xsl:choose>
-      <xsl:when test="@n">
-        <xsl:value-of select="@n"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:number level="any" from="/osis//verse" format="a"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="p">
-    <p><xsl:apply-templates/></p>
-  </xsl:template>
-  
-  <xsl:template match="p" mode="jesus">
-    <p><xsl:apply-templates mode="jesus"/></p>
-  </xsl:template>
-  
-  <!--=======================================================================-->
-  <xsl:template match="p" mode="print-notes">
-    <!-- FIXME: This ignores text in the note. -->
-    <!-- don't put para's in notes -->
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="w">
-    <!-- Output the content followed by all the lemmas and then all the morphs. -->
-    <xsl:apply-templates/>
-    
-    <!--
-        except when followed by a text node or non-printing node.
-        This is true whether the href is output or not.
-    -->
-    <xsl:variable name="siblings" select="../child::node()"/>
-    <xsl:variable name="next-position" select="position() + 1"/>
-    <xsl:if test="$siblings[$next-position] and name($siblings[$next-position]) != ''">
-      <xsl:text> </xsl:text>
-    </xsl:if>
-  </xsl:template>
-  
-  <xsl:template match="w" mode="jesus">
-    <!-- Output the content followed by all the lemmas and then all the morphs. -->
-    <xsl:apply-templates mode="jesus"/>
-    <!--
-        except when followed by a text node or non-printing node.
-        This is true whether the href is output or not.
-    -->
-    <xsl:variable name="siblings" select="../child::node()"/>
-    <xsl:variable name="next-position" select="position() + 1"/>
-    <xsl:if test="$siblings[$next-position] and name($siblings[$next-position]) != ''">
-      <xsl:text> </xsl:text>
-    </xsl:if>
-  </xsl:template>
-  
-  <!--=======================================================================-->
-  <xsl:template match="seg">
-    <xsl:choose>
-      <xsl:when test="starts-with(@type, 'color:')">
-        <font color="{substring-before(substring-after(@type, 'color: '), ';')}"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="starts-with(@type, 'font-size:')">
-        <font size="{substring-before(substring-after(@type, 'font-size: '), ';')}"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="@type = 'x-variant'">
-        <xsl:if test="@subType = 'x-class-1'">
-          <xsl:apply-templates/>
-        </xsl:if>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="seg" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="starts-with(@type, 'color:')">
-        <font color="{substring-before(substring-after(@type, 'color: '), ';')}"><xsl:apply-templates mode="jesus"/></font>
-      </xsl:when>
-      <xsl:when test="starts-with(@type, 'font-size:')">
-        <font size="{substring-before(substring-after(@type, 'font-size: '), ';')}"><xsl:apply-templates mode="jesus"/></font>
-      </xsl:when>
-      <xsl:when test="@type = 'x-variant'">
-        <xsl:if test="@subType = 'x-class:1'">
-          <xsl:apply-templates mode="jesus"/>
-        </xsl:if>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates mode="jesus"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <!--=======================================================================-->
-  <!-- expansion is OSIS, expan is TEI -->
-  <xsl:template match="abbr">
-    <font class="abbr">
-      <xsl:if test="@expansion">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expansion"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@expan">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expan"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:apply-templates/>
-    </font>
-  </xsl:template>
-
-  <xsl:template match="abbr" mode="jesus">
-    <font class="abbr">
-      <xsl:if test="@expansion">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expansion"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@expan">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expan"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:apply-templates mode="jesus"/>
-    </font>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="speaker[@who = 'Jesus']">
-    <span class="jesus"><xsl:apply-templates mode="jesus"/></span>
-  </xsl:template>
-
-  <xsl:template match="speaker">
-    <span class="speech"><xsl:apply-templates/></span>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="title[@subType ='x-preverse' or @subtype = 'x-preverse']">
-  <!-- Done by a line in [verse]
-    <h3 class="heading">
-      <xsl:apply-templates/>
-    </h3>
-  -->
-  </xsl:template>
-
-  <xsl:template match="title[@subType ='x-preverse' or @subtype = 'x-preverse']" mode="jesus">
-  <!-- Done by a line in [verse]
-    <h3 class="heading">
-      <xsl:apply-templates/>
-    </h3>
-  -->
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="title[@level]">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <xsl:choose>
-        <xsl:when test="@level = '1'">
-          <h1 class="level"><xsl:apply-templates/></h1>
-        </xsl:when>
-        <xsl:when test="@level = '2'">
-          <h2 class="level"><xsl:apply-templates/></h2>
-        </xsl:when>
-        <xsl:when test="@level = '3'">
-          <h3 class="level"><xsl:apply-templates/></h3>
-        </xsl:when>
-        <xsl:when test="@level = '4'">
-          <h4 class="level"><xsl:apply-templates/></h4>
-        </xsl:when>
-        <xsl:when test="@level = '5'">
-          <h5 class="level"><xsl:apply-templates/></h5>
-        </xsl:when>
-        <xsl:otherwise>
-          <h6 class="level"><xsl:apply-templates/></h6>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template match="title[@level]" mode="jesus">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <xsl:choose>
-        <xsl:when test="@level = '1'">
-          <h1 class="level"><xsl:apply-templates/></h1>
-        </xsl:when>
-        <xsl:when test="@level = '2'">
-          <h2 class="level"><xsl:apply-templates/></h2>
-        </xsl:when>
-        <xsl:when test="@level = '3'">
-          <h3 class="level"><xsl:apply-templates/></h3>
-        </xsl:when>
-        <xsl:when test="@level = '4'">
-          <h4 class="level"><xsl:apply-templates/></h4>
-        </xsl:when>
-        <xsl:when test="@level = '5'">
-          <h5 class="level"><xsl:apply-templates/></h5>
-        </xsl:when>
-        <xsl:otherwise>
-          <h6 class="level"><xsl:apply-templates/></h6>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="title">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <h2 class="heading"><xsl:apply-templates/></h2>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template match="title" mode="jesus">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <h2 class="heading"><xsl:apply-templates/></h2>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="reference">
-    <xsl:choose>
-      <xsl:when test="$XRef = 'true'">
-        <a href="bible://{@osisRef}"><xsl:apply-templates/></a>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="reference" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="$XRef = 'true'">
-        <a href="bible://{@osisRef}"><xsl:apply-templates mode="jesus"/></a>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates mode="jesus"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <!--=======================================================================-->
-  <xsl:template match="caption">
-    <div class="caption"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="caption" mode="jesus">
-    <div class="caption"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="catchWord">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="catchWord" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <!--
-      <cell> is handled shortly after <table> below and thus does not appear
-      here.
-  -->
-  
-  <xsl:template match="closer">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="closer" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <xsl:template match="date">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="date" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <xsl:template match="divineName">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-  
-  <xsl:template match="divineName" mode="jesus">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-  
-  <xsl:template match="figure">
-    <div class="figure">
-      <xsl:choose>
-        <xsl:when test="starts-with(@src, '/')">
-          <img src="{concat($baseURL, @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:when>
-        <xsl:otherwise>
-          <img src="{concat($baseURL, '/',  @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:otherwise>
-      </xsl:choose>
-      <xsl:apply-templates/>
-    </div>
-  </xsl:template>
-  
-  <xsl:template match="figure" mode="jesus">
-    <div class="figure">
-      <xsl:choose>
-        <xsl:when test="starts-with(@src, '/')">
-          <img src="{concat($baseURL, @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:when>
-        <xsl:otherwise>
-          <img src="{concat($baseURL, '/',  @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:otherwise>
-      </xsl:choose>
-      <xsl:apply-templates mode="jesus"/>
-    </div>
-  </xsl:template>
-  
-  <xsl:template match="foreign">
-    <em class="foreign"><xsl:apply-templates/></em>
-  </xsl:template>
-  
-  <xsl:template match="foreign" mode="jesus">
-    <em class="foreign"><xsl:apply-templates mode="jesus"/></em>
-  </xsl:template>
-  
-  <!-- This is a subheading. -->
-  <xsl:template match="head//head">
-    <h5 class="head"><xsl:apply-templates/></h5>
-  </xsl:template>
-  
-  <!-- This is a top-level heading. -->
-  <xsl:template match="head">
-    <h4 class="head"><xsl:apply-templates/></h4>
-  </xsl:template>
-  
-  <xsl:template match="index">
-    <a name="index{@id}" class="index"/>
-  </xsl:template>
-
-  <xsl:template match="inscription">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-
-  <xsl:template match="inscription" mode="jesus">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-
-  <xsl:template match="item">
-    <li class="item"><xsl:apply-templates/></li>
-  </xsl:template>
-
-  <xsl:template match="item" mode="jesus">
-    <li class="item"><xsl:apply-templates mode="jesus"/></li>
-  </xsl:template>
-  
-  <!--
-      <item> and <label> are covered by <list> below and so do not appear here.
-  -->
-
-  <xsl:template match="lg">
-    <div class="lg"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="lg" mode="jesus">
-    <div class="lg"><xsl:apply-templates mode="jesus"/></div>
-  </xsl:template>
-  
-  <xsl:template match="lg[@sID or @eID]"/>
-  <xsl:template match="lg[@sID or @eID]" mode="jesus"/>
-
-  <xsl:template match="l[@sID]"/>
-  <xsl:template match="l[@sID]" mode="jesus"/>
-
-  <xsl:template match="l[@eID]"><br/></xsl:template>
-  <xsl:template match="l[@eID]" mode="jesus"><br/></xsl:template>
-
-  <xsl:template match="l">
-    <xsl:apply-templates/><br/>
-  </xsl:template>
-  
-  <xsl:template match="l" mode="jesus">
-    <xsl:apply-templates mode="jesus"/><br/>
-  </xsl:template>
-
-  <!-- While a BR is a break, if it is immediately followed by punctuation,
-       indenting this rule can introduce whitespace.
-    -->
-  <xsl:template match="lb"><br /></xsl:template>
-  <xsl:template match="lb" mode="jesus"><br/></xsl:template>
-
-  <xsl:template match="list">
-    <xsl:choose>
-      <xsl:when test="label">
-        <!-- If there are <label>s in the list, it's a <dl>. -->
-        <dl class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::label">
-                <dt class="label"><xsl:apply-templates/></dt>
-              </xsl:when>
-              <xsl:when test="self::item">
-                <dd class="item"><xsl:apply-templates/></dd>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <dd class="list-wrapper"><xsl:apply-templates select="."/></dd>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </dl>
-      </xsl:when>
-
-      <xsl:otherwise>
-        <!-- If there are no <label>s in the list, it's a plain old <ul>. -->
-        <ul class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::item">
-                <li class="item"><xsl:apply-templates/></li>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <li class="list-wrapper"><xsl:apply-templates select="."/></li>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </ul>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-
-  <xsl:template match="list" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="label">
-        <!-- If there are <label>s in the list, it's a <dl>. -->
-        <dl class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::label">
-                <dt class="label"><xsl:apply-templates mode="jesus"/></dt>
-              </xsl:when>
-              <xsl:when test="self::item">
-                <dd class="item"><xsl:apply-templates mode="jesus"/></dd>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <dd class="list-wrapper"><xsl:apply-templates select="." mode="jesus"/></dd>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates mode="jesus"/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </dl>
-      </xsl:when>
-
-      <xsl:otherwise>
-        <!-- If there are no <label>s in the list, it's a plain old <ul>. -->
-        <ul class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::item">
-                <li class="item"><xsl:apply-templates mode="jesus"/></li>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <li class="list-wrapper"><xsl:apply-templates select="." mode="jesus"/></li>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates mode="jesus"/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </ul>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="mentioned">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="mentioned" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <!-- Milestones represent characteristics of the original manuscript.
-    == that are being preserved. For this reason, most are ignored.
-    ==
-    == The defined types are:
-    == column   Marks the end of a column where there is a multi-column display.
-    == footer   Marks the footer region of a page.
-    == halfLine Used to mark half-line units if not otherwise encoded.
-    == header   Marks the header region of a page.
-    == line     Marks line breaks, particularly important in recording appearance of an original text, such as a manuscript.
-    == pb       Marks a page break in a text.
-    == screen   Marks a preferred place for breaks in an on-screen rendering of the text.
-    == cQuote   Marks the location of a continuation quote mark, with marker containing the publishers mark.
-    -->
-  <!--  This is used by the KJV for paragraph markers. -->
-  <xsl:template match="milestone[@type = 'x-p']"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
-  <xsl:template match="milestone[@type = 'x-p']" mode="jesus"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
-
-  <xsl:template match="milestone[@type = 'cQuote']">
-    <xsl:value-of select="@marker"/>
-  </xsl:template>
-
-  <xsl:template match="milestone[@type = 'cQuote']" mode="jesus">
-    <xsl:value-of select="@marker"/>
-  </xsl:template>
-
-  <xsl:template match="milestone[@type = 'line']"><br/></xsl:template>
-
-  <xsl:template match="milestone[@type = 'line']" mode="jesus"><br/></xsl:template>
-
-  <!--
-    == Milestone start and end are deprecated.
-    == At this point we expect them to not be in the document.
-    == These have been replace with milestoneable elements.
-    -->
-  <xsl:template match="milestoneStart"/>
-  <xsl:template match="milestoneEnd"/>
-  
-  <xsl:template match="name">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="name" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <!-- If there is a milestoned q then just output a quotation mark -->
-  <xsl:template match="q[@sID or @eID]">
-    <xsl:choose>
-      <xsl:when test="@marker"><xsl:value-of select="@marker"/></xsl:when>
-      <!-- The chosen mark should be based on the work's author's locale. -->
-      <xsl:otherwise>"</xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="q[@sID or @eID]" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="@marker"><xsl:value-of select="@marker"/></xsl:when>
-      <!-- The chosen mark should be based on the work's author's locale. -->
-      <xsl:otherwise>"</xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="q[@who = 'Jesus']">
-    <span class="jesus"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></span>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'blockquote']">
-    <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></span>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'blockquote']" mode="jesus">
-    <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></span>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'citation']">
-    <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></span>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'citation']" mode="jesus">
-    <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></span>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'embedded']">
-    <xsl:choose>
-      <xsl:when test="@marker">
-        <xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <quote class="q"><xsl:apply-templates/></quote>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="q[@type = 'embedded']" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="@marker">
-      <xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <quote class="q"><xsl:apply-templates/></quote>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <!-- An alternate reading. -->
-  <xsl:template match="rdg">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-   <xsl:template match="rdg" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <!--
-      <row> is handled near <table> below and so does not appear here.
-  -->
-  
-  <xsl:template match="salute">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
- <!-- Avoid adding whitespace -->
-  <xsl:template match="salute" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <xsl:template match="signed">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="signed" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <xsl:template match="speech">
-    <div class="speech"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="speech" mode="jesus">
-    <div class="speech"><xsl:apply-templates mode="jesus"/></div>
-  </xsl:template>
-
-  <xsl:template match="table">
-    <table class="table">
-      <xsl:copy-of select="@rows|@cols"/>
-      <xsl:if test="head">
-        <thead class="head"><xsl:apply-templates select="head"/></thead>
-      </xsl:if>
-      <tbody><xsl:apply-templates select="row"/></tbody>
-    </table>
-  </xsl:template>
-
-  <xsl:template match="row">
-    <tr class="row"><xsl:apply-templates/></tr>
-  </xsl:template>
-  
-  <xsl:template match="cell">
-    <xsl:variable name="element-name">
-      <xsl:choose>
-        <xsl:when test="@role = 'label'">
-          <xsl:text>th</xsl:text>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:text>td</xsl:text>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:variable name="cell-direction">
-      <xsl:if test="@xml:lang">
-        <xsl:call-template name="getDirection">
-         <xsl:with-param name="lang"><xsl:value-of select="@xml:lang"/></xsl:with-param>
-        </xsl:call-template>
-      </xsl:if>
-    </xsl:variable>
-    <xsl:element name="{$element-name}">
-      <xsl:attribute name="class">cell</xsl:attribute>
-      <xsl:attribute name="valign">top</xsl:attribute>
-      <xsl:if test="@xml:lang">
-        <xsl:attribute name="dir">
-          <xsl:value-of select="$cell-direction"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="$cell-direction = 'rtl'">
-        <xsl:attribute name="align">
-          <xsl:value-of select="'right'"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@rows">
-        <xsl:attribute name="rowspan">
-          <xsl:value-of select="@rows"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@cols">
-        <xsl:attribute name="colspan">
-          <xsl:value-of select="@cols"/>
-        </xsl:attribute>
-      </xsl:if>
-      <!-- hack alert -->
-      <xsl:choose>
-        <xsl:when test="$cell-direction = 'rtl'">
-          <xsl:text>&#8235;</xsl:text><xsl:apply-templates/><xsl:text>&#8236;</xsl:text>
-        </xsl:when>
-        <xsl:when test="$cell-direction = 'ltr'">
-          <xsl:text>&#8234;</xsl:text><xsl:apply-templates/><xsl:text>&#8236;</xsl:text>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:apply-templates/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:element>
-  </xsl:template>
-
-  <xsl:template match="transChange">
-    <span><em><xsl:apply-templates/></em></span>
-  </xsl:template>
-  <xsl:template match="transChange" mode="jesus">
-    <span class="w"><em><xsl:apply-templates/></em></span>
-  </xsl:template>
-  
-  <!-- @type is OSIS, @rend is TEI -->
-  <xsl:template match="hi">
-    <xsl:variable name="style">
-      <xsl:choose>
-        <xsl:when test="@type">
-          <xsl:value-of select="@type"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="@rend"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:choose>
-      <xsl:when test="$style = 'acrostic'">
-        <xsl:apply-templates/>
-      </xsl:when>
-      <xsl:when test="$style = 'bold'">
-        <strong><xsl:apply-templates/></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'emphasis'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'illuminated'">
-        <strong><em><xsl:apply-templates/></em></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'italic'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'line-through'">
-        <span class="strike"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'normal'">
-        <span class="normal"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'small-caps'">
-        <span class="small-caps"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'sub'">
-        <sub><xsl:apply-templates/></sub>
-      </xsl:when>
-      <xsl:when test="$style = 'super'">
-        <sup><xsl:apply-templates/></sup>
-      </xsl:when>
-      <xsl:when test="$style = 'underline'">
-        <span class="underline"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'x-caps'">
-        <span class="caps"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="hi" mode="jesus">
-    <xsl:variable name="style">
-      <xsl:choose>
-        <xsl:when test="@type">
-          <xsl:value-of select="@type"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="@rend"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:choose>
-      <xsl:when test="$style = 'acrostic'">
-        <xsl:apply-templates/>
-      </xsl:when>
-      <xsl:when test="$style = 'bold'">
-        <strong><xsl:apply-templates/></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'emphasis'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'illuminated'">
-        <strong><em><xsl:apply-templates/></em></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'italic'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'line-through'">
-        <span class="strike"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'normal'">
-        <span class="normal"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'small-caps'">
-        <span class="small-caps"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'sub'">
-        <sub><xsl:apply-templates/></sub>
-      </xsl:when>
-      <xsl:when test="$style = 'super'">
-        <sup><xsl:apply-templates/></sup>
-      </xsl:when>
-      <xsl:when test="$style = 'underline'">
-        <span class="underline"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:when test="$style = 'x-caps'">
-        <span class="caps"><xsl:apply-templates/></span>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <!--
-    The following elements are actually TEI and there is some expectation
-    that these will make it into OSIS.
-  -->
-  <xsl:template match="superentry">
-    <!-- output each preverse element in turn -->
-    <xsl:for-each select="entry|entryFree">
-      <xsl:apply-templates/><br/><br/>
-    </xsl:for-each>
-  </xsl:template>
-
-  <xsl:template match="entry">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="entryFree">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="form">
-    <xsl:apply-templates/><br/>
-  </xsl:template>
-
-  <xsl:template match="orth">
-    <font class="orth"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="pron">
-    <font class="pron"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="etym">
-    <font class="etym"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="def">
-    <font class="def"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="usg">
-    <font class="usg"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="@xml:lang">
-    <xsl:variable name="dir">
-      <xsl:if test="@xml:lang">
-        <xsl:call-template name="getDirection">
-         <xsl:with-param name="lang"><xsl:value-of select="@xml:lang"/></xsl:with-param>
-        </xsl:call-template>
-      </xsl:if>
-    </xsl:variable>
-    <xsl:if test="$dir">
-      <xsl:attribute name="dir">
-        <xsl:value-of select="$dir"/>
-      </xsl:attribute>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template match="text()" mode="small-caps">
-  <xsl:value-of select="translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
-  </xsl:template>
-
-  <!--
-    The direction is deduced from the xml:lang attribute and is assumed to be meaningful for those elements.
-    Note: there is a bug that prevents dir=rtl from working.
-    see: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4296022 and 4866977
-  -->
-  <xsl:template name="getDirection">
-    <xsl:param name="lang"/>
-    <xsl:choose>
-      <xsl:when test="$lang = 'he' or $lang = 'ar' or $lang = 'fa' or $lang = 'ur' or $lang = 'syr'">
-        <xsl:value-of select="'rtl'"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:value-of select="'ltr'"/>
-      </xsl:otherwise>
-    </xsl:choose>
-   </xsl:template>
-   
-	<xsl:template name="string-replace-all">
-	<xsl:param name="text" />
-	<xsl:param name="replace" />
-	<xsl:param name="by" />
-	<xsl:choose>
-		<xsl:when test="contains($text, $replace)">
-			<xsl:value-of select="substring-before($text,$replace)" />
-			<xsl:value-of select="$by" />
-			<xsl:call-template name="string-replace-all">
-				<xsl:with-param name="text" select="substring-after($text,$replace)" />
-				<xsl:with-param name="replace" select="$replace" />
-				<xsl:with-param name="by" select="$by" />
-			</xsl:call-template>
-		</xsl:when>
-		<xsl:otherwise>
-			<xsl:value-of select="$text" />
-		</xsl:otherwise>
-	</xsl:choose>
-</xsl:template>  
-</xsl:stylesheet>

Deleted: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_interlinear.xsl
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_interlinear.xsl	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/old_interlinear.xsl	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,1555 +0,0 @@
-<?xml version="1.0"?>
-<!--
- * Distribution License:
- * JSword is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License, version 2.1 as published by
- * the Free Software Foundation. This program is distributed in the hope
- * that it will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The License is available on the internet at:
- *       http://www.gnu.org/copyleft/lgpl.html
- * or by writing to:
- *      Free Software Foundation, Inc.
- *      59 Temple Place - Suite 330
- *      Boston, MA 02111-1307, USA
- *
- * Copyright: 2005
- *     The copyright to this program is held by it's authors.
- *
- * ID: $Id: default.xsl 1943 2009-03-25 11:43:28Z dmsmith $
- -->
- <!--
- * Transforms OSIS to HTML for viewing within JSword browsers.
- * Note: There are custom protocols which the browser must handle.
- * 
- * @see gnu.lgpl.License for license details.
- *      The copyright to this program is held by it's authors.
- * @author Joe Walker [joe at eireneh dot com]
- * @author DM Smith [dmsmith555 at yahoo dot com]
- * @author Chris Burrell [chris at burrell dot me dot uk] 
- -->
- <xsl:stylesheet
-  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-  version="1.0"
-  xmlns:jsword="http://xml.apache.org/xalan/java"
-  extension-element-prefixes="jsword">
-
-  <!--  Version 3.0 is necessary to get br to work correctly. -->
-  <xsl:output method="html" version="3.0" omit-xml-declaration="yes" indent="no"/>
-
-  <!-- Be very careful about introducing whitespace into the document.
-       strip-space merely remove space between one tag and another tag.
-       This may cause significant whitespace to be removed.
-       
-       It is easy to have apply-templates on a line to itself which if
-       it encounters text before anything else will introduce whitespace.
-       With the browser we are using, span will introduce whitespace
-       but font does not. Therefore we use font as a span.
-    -->
-  <!-- gdef and hdef refer to hebrew and greek definitions keyed by strongs -->
-  <xsl:param name="greek.def.protocol" select="'gdef:'"/>
-  <xsl:param name="hebrew.def.protocol" select="'hdef:'"/>
-  <xsl:param name="lex.def.protocol" select="'lex:'"/>
-  <!-- currently these are not used, but they are for morphologic forms -->
-  <xsl:param name="greek.morph.protocol" select="'gmorph:'"/>
-  <xsl:param name="hebrew.morph.protocol" select="'hmorph:'"/>
-
-  <!-- The absolute base for relative references. -->
-  <xsl:param name="baseURL" select="''"/>
-
-  <!-- Whether to show Strongs or not -->
-  <xsl:param name="StrongsNumbers" select="'false'"/>
-
-  <!-- Whether to show morphologic forms or not -->
-  <xsl:param name="Morph" select="'false'"/>
-
-  <!-- Whether to start each verse on an new line or not -->
-  <xsl:param name="VLine" select="'false'"/>
-
-  <!-- Whether to show non-canonical "headings" or not -->
-  <xsl:param name="Headings" select="'true'"/>
-
-  <!-- Whether to show notes or not -->
-  <xsl:param name="Notes" select="'false'"/>
-
-  <!-- Whether to have linking cross references or not -->
-  <xsl:param name="XRef" select="'false'"/>
-
-  <!-- Whether to output no Verse numbers -->
-  <xsl:param name="NoVNum" select="'false'"/>
-
-  <!-- Whether to output Verse numbers or not -->
-  <xsl:param name="VNum" select="'true'"/>
-
-  <!-- Whether to output Chapter and Verse numbers or not -->
-  <xsl:param name="CVNum" select="'false'"/>
-
-  <!-- Whether to output Book, Chapter and Verse numbers or not -->
-  <xsl:param name="BCVNum" select="'false'"/>
-
-  <!-- Whether to output superscript verse numbers or normal size ones -->
-  <xsl:param name="TinyVNum" select="'true'"/>
-
-  <!-- The order of display. Hebrew is rtl (right to left) -->
-  <xsl:param name="direction" select="'ltr'"/>
-
-  <!-- Whether to show an interlinear and the provider helping with the lookup -->
-  <xsl:param name="Interlinear" select="'false'" />
-  <xsl:param name="interlinearVersion" select="''" />
-  <xsl:param name="interlinearReference" select="''" />
-
-  <!-- Create a global key factory from which OSIS ids will be generated -->
-  <xsl:variable name="keyf" select="jsword:org.crosswire.jsword.passage.PassageKeyFactory.instance()"/>
-  <!-- Create a global number shaper that can transform 0-9 into other number systems. -->
-  <xsl:variable name="shaper" select="jsword:org.crosswire.common.icu.NumberShaper.new()"/>
-  
-  <!--  set up interlinear provider, if we have requested it -->
-  <xsl:variable name="interlinearProvider" select="jsword:com.tyndalehouse.step.core.xsl.impl.InterlinearProviderImpl.new(string($interlinearVersion), string($interlinearReference))" />
-
-  <!--=======================================================================-->
-  <xsl:template match="/">
-      <div>
-        <!-- If there are notes, output a table with notes in the 2nd column. -->
-        <!-- There is a rendering bug which prevents the notes from adhering to the right edge. -->
-        <xsl:choose>
-          <xsl:when test="$Notes = 'true' and //note[not(@type = 'x-strongsMarkup')]">
-            <xsl:choose>
-              <xsl:when test="$direction != 'rtl'">
-                <table cols="2" cellpadding="5" cellspacing="5">
-                  <tr>
-                    <!-- The two rows are swapped until the bug is fixed. -->
-                    <td valign="top" class="notes">
-                      <p>&#160;</p>
-                      <xsl:apply-templates select="//verse" mode="print-notes"/>
-                    </td>
-                    <td valign="top" class="text">
-                      <xsl:apply-templates/>
-                    </td>
-                  </tr>
-                </table>
-              </xsl:when>
-              <xsl:otherwise>
-                <!-- reverse the table for Right to Left languages -->
-                <table cols="2" cellpadding="5" cellspacing="5">
-                  <!-- In a right to left, the alignment should be reversed too -->
-                  <tr align="right">
-                    <td valign="top" class="notes">
-                      <p>&#160;</p>
-                      <xsl:apply-templates select="//note" mode="print-notes"/>
-                    </td>
-                    <td valign="top" class="text">
-                      <xsl:apply-templates/>
-                    </td>
-                  </tr>
-                </table>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:apply-templates/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </div>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!--
-    == A proper OSIS document has osis as its root.
-    == We dig deeper for its content.
-    -->
-  <xsl:template match="osis">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!--
-    == An OSIS document may contain more that one work.
-    == Each work is held in an osisCorpus element.
-    == If there is only one work, then this element will (should) be absent.
-    == Process each document in turn.
-    == It might be reasonable to dig into the header element of each work
-    == and get its title.
-    == Otherwise, we ignore the header and work elements and just process
-    == the osisText elements.
-    -->
-  <xsl:template match="osisCorpus">
-    <xsl:apply-templates select="osisText"/>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!--
-    == Each work has an osisText element.
-    == We ignore the header and work elements and process its div elements.
-    == While divs can be milestoned, the osisText element requires container
-    == divs.
-    -->
-  <xsl:template match="osisText">
-    <xsl:apply-templates select="div"/>
-  </xsl:template>
-  
-  <!-- Ignore headers and its elements -->
-  <xsl:template match="header"/>
-  <xsl:template match="revisionDesc"/>
-  <xsl:template match="work"/>
-   <!-- <xsl:template match="title"/> who's parent is work -->
-  <xsl:template match="contributor"/>
-  <xsl:template match="creator"/>
-  <xsl:template match="subject"/>
-  <!-- <xsl:template match="date"/> who's parent is work -->
-  <xsl:template match="description"/>
-  <xsl:template match="publisher"/>
-  <xsl:template match="type"/>
-  <xsl:template match="format"/>
-  <xsl:template match="identifier"/>
-  <xsl:template match="source"/>
-  <xsl:template match="language"/>
-  <xsl:template match="relation"/>
-  <xsl:template match="coverage"/>
-  <xsl:template match="rights"/>
-  <xsl:template match="scope"/>
-  <xsl:template match="workPrefix"/>
-  <xsl:template match="castList"/>
-  <xsl:template match="castGroup"/>
-  <xsl:template match="castItem"/>
-  <xsl:template match="actor"/>
-  <xsl:template match="role"/>
-  <xsl:template match="roleDesc"/>
-  <xsl:template match="teiHeader"/>
-  <xsl:template match="refSystem"/>
-
-
-  <!-- Ignore titlePage -->
-  <xsl:template match="titlePage"/>
-
-  <!--=======================================================================-->
-  <!-- 
-    == Div provides the major containers for a work.
-    == Divs are milestoneable.
-    -->
-  <xsl:template match="div[@type='x-center']">
-    <div align="center">
-      <xsl:apply-templates/>
-    </div>
-  </xsl:template>
-
-  <xsl:template match="div">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="div" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!-- Handle verses as containers and as a start verse.                     -->
-  <xsl:template match="verse[not(@eID)]">
-    <!-- output each preverse element in turn -->
-    <xsl:for-each select=".//*[@subType = 'x-preverse' or @subtype = 'x-preverse']">
-      <xsl:choose>
-        <xsl:when test="local-name() = 'title'">
-          <!-- Always show canonical titles or if headings is turned on -->
-          <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-            <h3 class="heading"><xsl:apply-templates /></h3>
-          </xsl:if>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:apply-templates />
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:for-each>
-    <!-- Handle the KJV paragraph marker. -->
-    <xsl:if test="milestone[@type = 'x-p']"><br/><br/></xsl:if>
-    <!-- If the verse doesn't start on its own line and -->
-    <!-- the verse is not the first verse of a set of siblings, -->
-    <!-- output an extra space. -->
-    <xsl:if test="$VLine = 'false' and preceding-sibling::*[local-name() = 'verse']">
-      <xsl:text>&#160;</xsl:text>
-    </xsl:if>
-    <!-- Always output the verse -->
-    <xsl:choose>
-      <xsl:when test="$VLine = 'true'">
-        <div class="l"><a name="{@osisID}"><xsl:call-template name="versenum"/></a><xsl:apply-templates/></div>
-      </xsl:when>
-      <xsl:otherwise>
-        <span class="interlinear"><xsl:call-template name="versenum"/><xsl:apply-templates/></span>
-        <!-- Follow the verse with an extra space -->
-        <!-- when they don't start on lines to themselves -->
-        <xsl:text> </xsl:text>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="verse[not(@eID)]" mode="jesus">
-    <!-- If the verse doesn't start on its own line and -->
-    <!-- the verse is not the first verse of a set of siblings, -->
-    <!-- output an extra space. -->
-    <xsl:if test="$VLine = 'false' and preceding-sibling::*[local-name() = 'verse']">
-      <xsl:text>&#160;</xsl:text>
-    </xsl:if>
-    <xsl:variable name="title" select=".//title"/>
-    <xsl:if test="string-length($title) > 0">
-      <h3 class="heading"><xsl:value-of select="$title"/></h3>
-    </xsl:if>
-    <!-- Handle the KJV paragraph marker. -->
-    <xsl:if test="milestone[@type = 'x-p']"><br/><br/></xsl:if>
-    <!-- Always output the verse -->
-    <xsl:choose>
-      <xsl:when test="$VLine = 'true'">
-        <div class="l"><a name="{@osisID}"><xsl:call-template name="versenum"/></a><xsl:apply-templates mode="jesus"/></div>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:call-template name="versenum"/><xsl:apply-templates mode="jesus"/>
-        <!-- Follow the verse with an extra space -->
-        <!-- when they don't start on lines to themselves -->
-        <xsl:text> </xsl:text>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="verse" mode="print-notes">
-    <xsl:if test=".//note[not(@type) or not(@type = 'x-strongsMarkup')]">
-      <xsl:variable name="passage" select="jsword:getValidKey($keyf, @osisID)"/>
-      <a href="#{substring-before(concat(@osisID, ' '), ' ')}">
-        <xsl:value-of select="jsword:getName($passage)"/>
-      </a>
-      <xsl:apply-templates select=".//note" mode="print-notes" />
-      <div><xsl:text>&#160;</xsl:text></div>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template name="versenum">
-    <!-- Are verse numbers wanted? -->
-    <xsl:if test="$NoVNum = 'false'">
-      <!-- An osisID can be a space separated list of them -->
-      <xsl:variable name="firstOsisID" select="substring-before(concat(@osisID, ' '), ' ')"/>
-      <xsl:variable name="book" select="substring-before($firstOsisID, '.')"/>
-      <xsl:variable name="chapter" select="jsword:shape($shaper, substring-before(substring-after($firstOsisID, '.'), '.'))"/>
-      <!-- If n is present use it for the number -->
-      <xsl:variable name="verse">
-        <xsl:choose>
-          <xsl:when test="@n">
-            <xsl:value-of select="jsword:shape($shaper, string(@n))"/>
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:value-of select="jsword:shape($shaper, substring-after(substring-after($firstOsisID, '.'), '.'))"/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </xsl:variable>
-      <xsl:variable name="versenum">
-        <xsl:choose>
-          <xsl:when test="$BCVNum = 'true'">
-            <xsl:variable name="passage" select="jsword:getValidKey($keyf, @osisID)"/>
-            <xsl:value-of select="jsword:getName($passage)"/>
-          </xsl:when>
-          <xsl:when test="$CVNum = 'true'">
-            <xsl:value-of select="concat($chapter, ' : ', $verse)"/>
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:value-of select="$verse"/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </xsl:variable>
-      <!--
-        == Surround versenum with dup
-        -->
-      <xsl:choose>
-        <xsl:when test="$TinyVNum = 'true' and $Notes = 'true'">
-          <span class="w"><a name="{@osisID}"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></a></span>
-        </xsl:when>
-        <xsl:when test="$TinyVNum = 'true' and $Notes = 'false'">
-          <span class="w"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></span>
-        </xsl:when>
-        <xsl:when test="$TinyVNum = 'false' and $Notes = 'true'">
-          <a name="{@osisID}">(<xsl:value-of select="$versenum"/>)</a>
-          <xsl:text> </xsl:text>
-        </xsl:when>
-        <xsl:otherwise>
-          (<xsl:value-of select="$versenum"/>)
-          <xsl:text> </xsl:text>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-    <xsl:if test="$VNum = 'false' and $Notes = 'true'">
-      <a name="{@osisID}"></a>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="a">
-    <a href="{@href}"><xsl:apply-templates/></a>
-  </xsl:template>
-
-  <xsl:template match="a" mode="jesus">
-    <a href="{@href}"><xsl:apply-templates mode="jesus"/></a>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <!-- When we encounter a note, we merely output a link to the note. -->
-  <xsl:template match="note[@type = 'x-strongsMarkup']"/>
-  <xsl:template match="note[@type = 'x-strongsMarkup']" mode="jesus"/>
-  <xsl:template match="note[@type = 'x-strongsMarkup']" mode="print-notes"/>
-
-  <xsl:template match="note">
-    <xsl:if test="$Notes = 'true'">
-      <!-- If there is a following sibling that is a note, emit a separator -->
-      <xsl:variable name="siblings" select="../child::node()"/>
-      <xsl:variable name="next-position" select="position() + 1"/>
-      <xsl:choose>
-        <xsl:when test="name($siblings[$next-position]) = 'note'">
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a>, </sup>
-        </xsl:when>
-        <xsl:otherwise>
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a></sup>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template match="note" mode="jesus">
-    <xsl:if test="$Notes = 'true'">
-     <!-- If there is a following sibling that is a note, emit a separator -->
-      <xsl:variable name="siblings" select="../child::node()"/>
-      <xsl:variable name="next-position" select="position() + 1"/>
-      <xsl:choose>
-        <xsl:when test="$siblings[$next-position] and name($siblings[$next-position]) = 'note'">
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a>, </sup>
-        </xsl:when>
-        <xsl:otherwise>
-          <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a></sup>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="note" mode="print-notes">
-    <div class="margin">
-      <strong><xsl:call-template name="generateNoteXref"/></strong>
-      <a name="note-{generate-id(.)}">
-        <xsl:text> </xsl:text>
-      </a>
-      <xsl:apply-templates/>
-    </div>
-  </xsl:template>
-
-  <!--
-    == If the n attribute is present then use that for the cross ref otherwise create a letter.
-    == Note: numbering restarts with each verse.
-    -->
-  <xsl:template name="generateNoteXref">
-    <xsl:choose>
-      <xsl:when test="@n">
-        <xsl:value-of select="@n"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:number level="any" from="/osis//verse" format="a"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="p">
-    <p><xsl:apply-templates/></p>
-  </xsl:template>
-  
-  <xsl:template match="p" mode="jesus">
-    <p><xsl:apply-templates mode="jesus"/></p>
-  </xsl:template>
-  
-  <!--=======================================================================-->
-  <xsl:template match="p" mode="print-notes">
-    <!-- FIXME: This ignores text in the note. -->
-    <!-- don't put para's in notes -->
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="w">
-    <!-- Output the content followed by all the lemmas and then all the morphs. -->
-    <xsl:variable name="innerWordText"><xsl:apply-templates/></xsl:variable>
-    <xsl:variable name="isNextSiblingText" select="following-sibling::*[1]/text() = ''" />    
-  	<xsl:variable name="nextNodeCharClass" select="''" />
-  	<xsl:if test="following-sibling::*[1]/text() != ''">
-  		<xsl:variable name="nextNodeCharClass" select="'punctuNext'" />
-  	</xsl:if>
-  	<span class="w">
-  	<span class="text">
-    <xsl:choose>
-    	<xsl:when test="not(normalize-space($innerWordText))">&#160;</xsl:when>
-    	<xsl:otherwise><xsl:value-of select="$innerWordText" /></xsl:otherwise>	
-    </xsl:choose></span>
-    <xsl:if test="$StrongsNumbers = 'true' and (starts-with(@lemma, 'x-Strongs:') or starts-with(@lemma, 'strong:'))">
-      <xsl:call-template name="lemma">
-        <xsl:with-param name="lemma" select="@lemma"/>
-      </xsl:call-template>
-    </xsl:if>
-    <xsl:if test="$Morph = 'true' and (starts-with(@morph, 'x-Robinson:') or starts-with(@morph, 'robinson:'))">
-      <xsl:call-template name="morph">
-        <xsl:with-param name="morph" select="@morph"/>
-      </xsl:call-template>
-    </xsl:if>
-    <xsl:if test="$StrongsNumbers = 'true' and starts-with(@lemma, 'lemma.Strong:')">
-      <xsl:call-template name="lemma">
-        <xsl:with-param name="lemma" select="@lemma"/>
-      </xsl:call-template>
-    </xsl:if>
-    <xsl:if test="$Interlinear = 'true'">
-      <xsl:call-template name="interlinear">
-        <xsl:with-param name="lemma" select="@lemma" />
-        <xsl:with-param name="morph" select="@morph" />
-        <xsl:with-param name="osisID" select="../@osisID" />
-      </xsl:call-template>
-    </xsl:if>
-    
-    <!--
-        except when followed by a text node or non-printing node.
-        This is true whether the href is output or not.
-    -->
-    <xsl:variable name="siblings" select="../child::node()"/>
-    <xsl:variable name="next-position" select="position() + 1"/>
-    <xsl:if test="$siblings[$next-position] and name($siblings[$next-position]) != ''">
-      <xsl:text> </xsl:text>
-    </xsl:if>
-    </span>
-  </xsl:template>
-  
-  <xsl:template match="w" mode="jesus">
-    <!-- Output the content followed by all the lemmas and then all the morphs. -->
-    <xsl:apply-templates mode="jesus"/>
-    <xsl:if test="$StrongsNumbers = 'true' and (starts-with(@lemma, 'x-Strongs:') or starts-with(@lemma, 'strong:'))">
-      <xsl:call-template name="lemma">
-        <xsl:with-param name="lemma" select="@lemma"/>
-      </xsl:call-template>
-    </xsl:if>
-    <xsl:if test="$Morph = 'true' and (starts-with(@morph, 'x-Robinson:') or starts-with(@morph, 'robinson:'))">
-      <xsl:call-template name="morph">
-        <xsl:with-param name="morph" select="@morph"/>
-      </xsl:call-template>
-    </xsl:if>
-    <!--
-        except when followed by a text node or non-printing node.
-        This is true whether the href is output or not.
-    -->
-    <xsl:variable name="siblings" select="../child::node()"/>
-    <xsl:variable name="next-position" select="position() + 1"/>
-    <xsl:if test="$siblings[$next-position] and name($siblings[$next-position]) != ''">
-      <xsl:text> </xsl:text>
-    </xsl:if>
-  </xsl:template>
-  
-  <xsl:template name="lemma">
-    <xsl:param name="lemma"/>
-    <xsl:param name="part" select="0"/>
-    <xsl:param name="className" />
-    <xsl:param name="finalText" />
-    
-    <xsl:variable name="orig-lemma" select="substring-after($lemma, ':')"/>
-    <xsl:variable name="protocol">
-      <xsl:choose>
-        <xsl:when test="substring($orig-lemma, 1, 1) = 'H'">
-          <xsl:value-of select="$hebrew.def.protocol"/>
-        </xsl:when>
-        <xsl:when test="substring($orig-lemma, 1, 1) = 'G'">
-          <xsl:value-of select="$greek.def.protocol"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="$lex.def.protocol"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:variable name="separator">
-      <xsl:choose>
-        <xsl:when test="contains($orig-lemma, '|') ">
-          <xsl:value-of select="'|'"/>
-        </xsl:when>
-        <xsl:when test="contains($orig-lemma, ' ')">
-          <xsl:value-of select="' '"/>
-        </xsl:when>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:variable name="sub">
-      <xsl:choose>
-        <xsl:when test="$separator != '' and $part = '0'">
-          <xsl:value-of select="$part + 1"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="$part"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:choose>
-    <!--  TODO, we change this and put a condition above to determine whether we chop off from 1, or 2 -->
-      <xsl:when test="$protocol = $lex.def.protocol">
-        <font class="lex">[<xsl:value-of select="$orig-lemma"/>]</font>
-      </xsl:when>
-      <xsl:when test="$separator = ''">
-        <span class="strongs {$className} {$orig-lemma}"><xsl:value-of select="concat($finalText, ' ', format-number(substring($orig-lemma, 2), '#'))" />
-        </span>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:variable name="processedLemma" select="substring-before($orig-lemma, $separator)" />
-        <xsl:call-template name="lemma">
-          <xsl:with-param name="lemma" select="substring-after($lemma, $separator)"/>
-          <xsl:with-param name="className" select="concat($className, $processedLemma)" />
-          <xsl:with-param name="finalText" select="concat($finalText, ' ', format-number(substring($processedLemma,2),'#'))" />
-          <xsl:with-param name="part">
-            <xsl:choose>
-              <xsl:when test="$sub">
-                <xsl:value-of select="$sub + 1"/>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:value-of select="1"/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:with-param>
-        </xsl:call-template>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template name="morph">
-    <xsl:param name="morph"/>
-    <xsl:param name="part" select="0"/>
-    <xsl:variable name="orig-work" select="substring-before($morph, ':')"/>
-    <xsl:variable name="orig-morph" select="substring-after($morph, ':')"/>
-    <xsl:variable name="protocol">
-      <xsl:choose>
-        <xsl:when test="starts-with($orig-work, 'x-Robinson') or starts-with($orig-work, 'robinson')">
-          <xsl:value-of select="$greek.morph.protocol"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="$hebrew.morph.protocol"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:variable name="separator">
-      <xsl:choose>
-        <xsl:when test="contains($orig-morph, '|')">
-          <xsl:value-of select="'|'"/>
-        </xsl:when>
-        <xsl:when test="contains($orig-morph, ' ')">
-          <xsl:value-of select="' '"/>
-        </xsl:when>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:variable name="sub">
-      <xsl:choose>
-        <xsl:when test="$separator != '' and $part = '0'">
-          <xsl:value-of select="$part + 1"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="$part"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:choose>
-      <xsl:when test="$separator = ''">
-        <!-- <sub class="morph"><a href="{$protocol}{$orig-morph}">M<xsl:number level="any" from="/osis//verse" format="1"/><xsl:number value="$sub" format="a"/></a></sub> -->
-        <sub class="morph"><a href="{$protocol}{$orig-morph}"><xsl:value-of select="$orig-morph"/></a></sub>
-      </xsl:when>
-      <xsl:otherwise>
-        <!-- <sub class="morph"><a href="{$protocol}{substring-before($orig-morph, $separator)}">M<xsl:number level="single" from="/osis//verse" format="1"/><xsl:number value="$sub" format="a"/></a>, </sub> -->
-        <sub class="morph"><a href="{$protocol}{substring-before($orig-morph, $separator)}"><xsl:value-of select="substring-before($orig-morph, $separator)"/></a>, </sub>
-        <xsl:call-template name="morph">
-          <xsl:with-param name="morph" select="substring-after($morph, $separator)"/>
-          <xsl:with-param name="part">
-            <xsl:choose>
-              <xsl:when test="$sub">
-                <xsl:value-of select="$sub + 1"/>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:value-of select="1"/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:with-param>
-        </xsl:call-template>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template name="interlinear">
-    <xsl:param name="lemma" select="''"/>
-    <xsl:param name="morph" select="''"/>
-    <xsl:param name="osisID" />
-    <xsl:variable name="interlinearWord" select="jsword:getWord($interlinearProvider, $osisID, $lemma, $morph)"/>
-    <xsl:choose>
-    	<xsl:when test="normalize-space($interlinearWord) = ''" >&#160;</xsl:when>
-    	<xsl:otherwise><span class="interlinearText"><xsl:value-of select="$interlinearWord"/></span></xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-
-  <!--=======================================================================-->
-  <xsl:template match="seg">
-    <xsl:choose>
-      <xsl:when test="starts-with(@type, 'color:')">
-        <font color="{substring-before(substring-after(@type, 'color: '), ';')}"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="starts-with(@type, 'font-size:')">
-        <font size="{substring-before(substring-after(@type, 'font-size: '), ';')}"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="@type = 'x-variant'">
-        <xsl:if test="@subType = 'x-class-1'">
-          <xsl:apply-templates/>
-        </xsl:if>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="seg" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="starts-with(@type, 'color:')">
-        <font color="{substring-before(substring-after(@type, 'color: '), ';')}"><xsl:apply-templates mode="jesus"/></font>
-      </xsl:when>
-      <xsl:when test="starts-with(@type, 'font-size:')">
-        <font size="{substring-before(substring-after(@type, 'font-size: '), ';')}"><xsl:apply-templates mode="jesus"/></font>
-      </xsl:when>
-      <xsl:when test="@type = 'x-variant'">
-        <xsl:if test="@subType = 'x-class:1'">
-          <xsl:apply-templates mode="jesus"/>
-        </xsl:if>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates mode="jesus"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <!--=======================================================================-->
-  <!-- expansion is OSIS, expan is TEI -->
-  <xsl:template match="abbr">
-    <font class="abbr">
-      <xsl:if test="@expansion">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expansion"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@expan">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expan"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:apply-templates/>
-    </font>
-  </xsl:template>
-
-  <xsl:template match="abbr" mode="jesus">
-    <font class="abbr">
-      <xsl:if test="@expansion">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expansion"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@expan">
-        <xsl:attribute name="title">
-          <xsl:value-of select="@expan"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:apply-templates mode="jesus"/>
-    </font>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="speaker[@who = 'Jesus']">
-    <font class="jesus"><xsl:apply-templates mode="jesus"/></font>
-  </xsl:template>
-
-  <xsl:template match="speaker">
-    <font class="speech"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="title[@subType ='x-preverse' or @subtype = 'x-preverse']">
-  <!-- Done by a line in [verse]
-    <h3 class="heading">
-      <xsl:apply-templates/>
-    </h3>
-  -->
-  </xsl:template>
-
-  <xsl:template match="title[@subType ='x-preverse' or @subtype = 'x-preverse']" mode="jesus">
-  <!-- Done by a line in [verse]
-    <h3 class="heading">
-      <xsl:apply-templates/>
-    </h3>
-  -->
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="title[@level]">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <xsl:choose>
-        <xsl:when test="@level = '1'">
-          <h1 class="level"><xsl:apply-templates/></h1>
-        </xsl:when>
-        <xsl:when test="@level = '2'">
-          <h2 class="level"><xsl:apply-templates/></h2>
-        </xsl:when>
-        <xsl:when test="@level = '3'">
-          <h3 class="level"><xsl:apply-templates/></h3>
-        </xsl:when>
-        <xsl:when test="@level = '4'">
-          <h4 class="level"><xsl:apply-templates/></h4>
-        </xsl:when>
-        <xsl:when test="@level = '5'">
-          <h5 class="level"><xsl:apply-templates/></h5>
-        </xsl:when>
-        <xsl:otherwise>
-          <h6 class="level"><xsl:apply-templates/></h6>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template match="title[@level]" mode="jesus">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <xsl:choose>
-        <xsl:when test="@level = '1'">
-          <h1 class="level"><xsl:apply-templates/></h1>
-        </xsl:when>
-        <xsl:when test="@level = '2'">
-          <h2 class="level"><xsl:apply-templates/></h2>
-        </xsl:when>
-        <xsl:when test="@level = '3'">
-          <h3 class="level"><xsl:apply-templates/></h3>
-        </xsl:when>
-        <xsl:when test="@level = '4'">
-          <h4 class="level"><xsl:apply-templates/></h4>
-        </xsl:when>
-        <xsl:when test="@level = '5'">
-          <h5 class="level"><xsl:apply-templates/></h5>
-        </xsl:when>
-        <xsl:otherwise>
-          <h6 class="level"><xsl:apply-templates/></h6>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="title">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <h2 class="heading"><xsl:apply-templates/></h2>
-    </xsl:if>
-  </xsl:template>
-
-  <xsl:template match="title" mode="jesus">
-    <!-- Always show canonical titles or if headings is turned on -->
-    <xsl:if test="@canonical = 'true' or $Headings = 'true'">
-      <h2 class="heading"><xsl:apply-templates/></h2>
-    </xsl:if>
-  </xsl:template>
-
-  <!--=======================================================================-->
-  <xsl:template match="reference">
-    <xsl:choose>
-      <xsl:when test="$XRef = 'true'">
-        <a href="bible://{@osisRef}"><xsl:apply-templates/></a>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="reference" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="$XRef = 'true'">
-        <a href="bible://{@osisRef}"><xsl:apply-templates mode="jesus"/></a>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates mode="jesus"/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <!--=======================================================================-->
-  <xsl:template match="caption">
-    <div class="caption"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="caption" mode="jesus">
-    <div class="caption"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="catchWord">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="catchWord" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <!--
-      <cell> is handled shortly after <table> below and thus does not appear
-      here.
-  -->
-  
-  <xsl:template match="closer">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="closer" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <xsl:template match="date">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="date" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <xsl:template match="divineName">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-  
-  <xsl:template match="divineName" mode="jesus">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-  
-  <xsl:template match="figure">
-    <div class="figure">
-      <xsl:choose>
-        <xsl:when test="starts-with(@src, '/')">
-          <img src="{concat($baseURL, @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:when>
-        <xsl:otherwise>
-          <img src="{concat($baseURL, '/',  @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:otherwise>
-      </xsl:choose>
-      <xsl:apply-templates/>
-    </div>
-  </xsl:template>
-  
-  <xsl:template match="figure" mode="jesus">
-    <div class="figure">
-      <xsl:choose>
-        <xsl:when test="starts-with(@src, '/')">
-          <img src="{concat($baseURL, @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:when>
-        <xsl:otherwise>
-          <img src="{concat($baseURL, '/',  @src)}"/>   <!-- FIXME: Not necessarily an image... -->
-        </xsl:otherwise>
-      </xsl:choose>
-      <xsl:apply-templates mode="jesus"/>
-    </div>
-  </xsl:template>
-  
-  <xsl:template match="foreign">
-    <em class="foreign"><xsl:apply-templates/></em>
-  </xsl:template>
-  
-  <xsl:template match="foreign" mode="jesus">
-    <em class="foreign"><xsl:apply-templates mode="jesus"/></em>
-  </xsl:template>
-  
-  <!-- This is a subheading. -->
-  <xsl:template match="head//head">
-    <h5 class="head"><xsl:apply-templates/></h5>
-  </xsl:template>
-  
-  <!-- This is a top-level heading. -->
-  <xsl:template match="head">
-    <h4 class="head"><xsl:apply-templates/></h4>
-  </xsl:template>
-  
-  <xsl:template match="index">
-    <a name="index{@id}" class="index"/>
-  </xsl:template>
-
-  <xsl:template match="inscription">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-
-  <xsl:template match="inscription" mode="jesus">
-    <xsl:apply-templates mode="small-caps"/>
-  </xsl:template>
-
-  <xsl:template match="item">
-    <li class="item"><xsl:apply-templates/></li>
-  </xsl:template>
-
-  <xsl:template match="item" mode="jesus">
-    <li class="item"><xsl:apply-templates mode="jesus"/></li>
-  </xsl:template>
-  
-  <!--
-      <item> and <label> are covered by <list> below and so do not appear here.
-  -->
-
-  <xsl:template match="lg">
-    <div class="lg"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="lg" mode="jesus">
-    <div class="lg"><xsl:apply-templates mode="jesus"/></div>
-  </xsl:template>
-  
-  <xsl:template match="lg[@sID or @eID]"/>
-  <xsl:template match="lg[@sID or @eID]" mode="jesus"/>
-
-  <xsl:template match="l[@sID]"/>
-  <xsl:template match="l[@sID]" mode="jesus"/>
-
-  <xsl:template match="l[@eID]"><br/></xsl:template>
-  <xsl:template match="l[@eID]" mode="jesus"><br/></xsl:template>
-
-  <xsl:template match="l">
-    <xsl:apply-templates/><br/>
-  </xsl:template>
-  
-  <xsl:template match="l" mode="jesus">
-    <xsl:apply-templates mode="jesus"/><br/>
-  </xsl:template>
-
-  <!-- While a BR is a break, if it is immediately followed by punctuation,
-       indenting this rule can introduce whitespace.
-    -->
-  <xsl:template match="lb"><br/></xsl:template>
-  <xsl:template match="lb" mode="jesus"><br/></xsl:template>
-
-  <xsl:template match="list">
-    <xsl:choose>
-      <xsl:when test="label">
-        <!-- If there are <label>s in the list, it's a <dl>. -->
-        <dl class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::label">
-                <dt class="label"><xsl:apply-templates/></dt>
-              </xsl:when>
-              <xsl:when test="self::item">
-                <dd class="item"><xsl:apply-templates/></dd>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <dd class="list-wrapper"><xsl:apply-templates select="."/></dd>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </dl>
-      </xsl:when>
-
-      <xsl:otherwise>
-        <!-- If there are no <label>s in the list, it's a plain old <ul>. -->
-        <ul class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::item">
-                <li class="item"><xsl:apply-templates/></li>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <li class="list-wrapper"><xsl:apply-templates select="."/></li>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </ul>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-
-  <xsl:template match="list" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="label">
-        <!-- If there are <label>s in the list, it's a <dl>. -->
-        <dl class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::label">
-                <dt class="label"><xsl:apply-templates mode="jesus"/></dt>
-              </xsl:when>
-              <xsl:when test="self::item">
-                <dd class="item"><xsl:apply-templates mode="jesus"/></dd>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <dd class="list-wrapper"><xsl:apply-templates select="." mode="jesus"/></dd>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates mode="jesus"/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </dl>
-      </xsl:when>
-
-      <xsl:otherwise>
-        <!-- If there are no <label>s in the list, it's a plain old <ul>. -->
-        <ul class="list">
-          <xsl:for-each select="node()">
-            <xsl:choose>
-              <xsl:when test="self::item">
-                <li class="item"><xsl:apply-templates mode="jesus"/></li>
-              </xsl:when>
-              <xsl:when test="self::list">
-                <li class="list-wrapper"><xsl:apply-templates select="." mode="jesus"/></li>
-              </xsl:when>
-              <xsl:otherwise>
-                <xsl:apply-templates mode="jesus"/>
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:for-each>
-        </ul>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="mentioned">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
-  <xsl:template match="mentioned" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-  
-  <!-- Milestones represent characteristics of the original manuscript.
-    == that are being preserved. For this reason, most are ignored.
-    ==
-    == The defined types are:
-    == column   Marks the end of a column where there is a multi-column display.
-    == footer   Marks the footer region of a page.
-    == halfLine Used to mark half-line units if not otherwise encoded.
-    == header   Marks the header region of a page.
-    == line     Marks line breaks, particularly important in recording appearance of an original text, such as a manuscript.
-    == pb       Marks a page break in a text.
-    == screen   Marks a preferred place for breaks in an on-screen rendering of the text.
-    == cQuote   Marks the location of a continuation quote mark, with marker containing the publishers mark.
-    -->
-  <!--  This is used by the KJV for paragraph markers. -->
-  <xsl:template match="milestone[@type = 'x-p']"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
-  <xsl:template match="milestone[@type = 'x-p']" mode="jesus"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
-
-  <xsl:template match="milestone[@type = 'cQuote']">
-    <xsl:value-of select="@marker"/>
-  </xsl:template>
-
-  <xsl:template match="milestone[@type = 'cQuote']" mode="jesus">
-    <xsl:value-of select="@marker"/>
-  </xsl:template>
-
-  <xsl:template match="milestone[@type = 'line']"><br/></xsl:template>
-
-  <xsl:template match="milestone[@type = 'line']" mode="jesus"><br/></xsl:template>
-
-  <!--
-    == Milestone start and end are deprecated.
-    == At this point we expect them to not be in the document.
-    == These have been replace with milestoneable elements.
-    -->
-  <xsl:template match="milestoneStart"/>
-  <xsl:template match="milestoneEnd"/>
-  
-  <xsl:template match="name">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="name" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <!-- If there is a milestoned q then just output a quotation mark -->
-  <xsl:template match="q[@sID or @eID]">
-    <xsl:choose>
-      <xsl:when test="@marker"><xsl:value-of select="@marker"/></xsl:when>
-      <!-- The chosen mark should be based on the work's author's locale. -->
-      <xsl:otherwise>"</xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="q[@sID or @eID]" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="@marker"><xsl:value-of select="@marker"/></xsl:when>
-      <!-- The chosen mark should be based on the work's author's locale. -->
-      <xsl:otherwise>"</xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="q[@who = 'Jesus']">
-    <font class="jesus"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></font>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'blockquote']">
-    <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></blockquote>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'blockquote']" mode="jesus">
-    <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></blockquote>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'citation']">
-    <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></blockquote>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'citation']" mode="jesus">
-    <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></blockquote>
-  </xsl:template>
-
-  <xsl:template match="q[@type = 'embedded']">
-    <xsl:choose>
-      <xsl:when test="@marker">
-        <xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <quote class="q"><xsl:apply-templates/></quote>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <xsl:template match="q[@type = 'embedded']" mode="jesus">
-    <xsl:choose>
-      <xsl:when test="@marker">
-      <xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <quote class="q"><xsl:apply-templates/></quote>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-  
-  <!-- An alternate reading. -->
-  <xsl:template match="rdg">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-   <xsl:template match="rdg" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <!--
-      <row> is handled near <table> below and so does not appear here.
-  -->
-  
-  <xsl:template match="salute">
-    <xsl:apply-templates/>
-  </xsl:template>
-  
- <!-- Avoid adding whitespace -->
-  <xsl:template match="salute" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <xsl:template match="signed">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="signed" mode="jesus">
-    <xsl:apply-templates mode="jesus"/>
-  </xsl:template>
-
-  <xsl:template match="speech">
-    <div class="speech"><xsl:apply-templates/></div>
-  </xsl:template>
-  
-  <xsl:template match="speech" mode="jesus">
-    <div class="speech"><xsl:apply-templates mode="jesus"/></div>
-  </xsl:template>
-
-  <xsl:template match="table">
-    <table class="table">
-      <xsl:copy-of select="@rows|@cols"/>
-      <xsl:if test="head">
-        <thead class="head"><xsl:apply-templates select="head"/></thead>
-      </xsl:if>
-      <tbody><xsl:apply-templates select="row"/></tbody>
-    </table>
-  </xsl:template>
-
-  <xsl:template match="row">
-    <tr class="row"><xsl:apply-templates/></tr>
-  </xsl:template>
-  
-  <xsl:template match="cell">
-    <xsl:variable name="element-name">
-      <xsl:choose>
-        <xsl:when test="@role = 'label'">
-          <xsl:text>th</xsl:text>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:text>td</xsl:text>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:variable name="cell-direction">
-      <xsl:if test="@xml:lang">
-        <xsl:call-template name="getDirection">
-         <xsl:with-param name="lang"><xsl:value-of select="@xml:lang"/></xsl:with-param>
-        </xsl:call-template>
-      </xsl:if>
-    </xsl:variable>
-    <xsl:element name="{$element-name}">
-      <xsl:attribute name="class">cell</xsl:attribute>
-      <xsl:attribute name="valign">top</xsl:attribute>
-      <xsl:if test="@xml:lang">
-        <xsl:attribute name="dir">
-          <xsl:value-of select="$cell-direction"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="$cell-direction = 'rtl'">
-        <xsl:attribute name="align">
-          <xsl:value-of select="'right'"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@rows">
-        <xsl:attribute name="rowspan">
-          <xsl:value-of select="@rows"/>
-        </xsl:attribute>
-      </xsl:if>
-      <xsl:if test="@cols">
-        <xsl:attribute name="colspan">
-          <xsl:value-of select="@cols"/>
-        </xsl:attribute>
-      </xsl:if>
-      <!-- hack alert -->
-      <xsl:choose>
-        <xsl:when test="$cell-direction = 'rtl'">
-          <xsl:text>&#8235;</xsl:text><xsl:apply-templates/><xsl:text>&#8236;</xsl:text>
-        </xsl:when>
-        <xsl:when test="$cell-direction = 'ltr'">
-          <xsl:text>&#8234;</xsl:text><xsl:apply-templates/><xsl:text>&#8236;</xsl:text>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:apply-templates/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:element>
-  </xsl:template>
-
-  <xsl:template match="transChange">
-    <span><em><xsl:apply-templates/></em></span>
-  </xsl:template>
-  <xsl:template match="transChange" mode="jesus">
-    <span class="w"><em><xsl:apply-templates/></em></span>
-  </xsl:template>
-  
-  <!-- @type is OSIS, @rend is TEI -->
-  <xsl:template match="hi">
-    <xsl:variable name="style">
-      <xsl:choose>
-        <xsl:when test="@type">
-          <xsl:value-of select="@type"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="@rend"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:choose>
-      <xsl:when test="$style = 'acrostic'">
-        <xsl:apply-templates/>
-      </xsl:when>
-      <xsl:when test="$style = 'bold'">
-        <strong><xsl:apply-templates/></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'emphasis'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'illuminated'">
-        <strong><em><xsl:apply-templates/></em></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'italic'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'line-through'">
-        <font class="strike"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="$style = 'normal'">
-        <font class="normal"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="$style = 'small-caps'">
-        <font class="small-caps"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="$style = 'sub'">
-        <sub><xsl:apply-templates/></sub>
-      </xsl:when>
-      <xsl:when test="$style = 'super'">
-        <sup><xsl:apply-templates/></sup>
-      </xsl:when>
-      <xsl:when test="$style = 'underline'">
-        <u><xsl:apply-templates/></u>
-      </xsl:when>
-      <xsl:when test="$style = 'x-caps'">
-        <font class="caps"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <xsl:template match="hi" mode="jesus">
-    <xsl:variable name="style">
-      <xsl:choose>
-        <xsl:when test="@type">
-          <xsl:value-of select="@type"/>
-        </xsl:when>
-        <xsl:otherwise>
-          <xsl:value-of select="@rend"/>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:variable>
-    <xsl:choose>
-      <xsl:when test="$style = 'acrostic'">
-        <xsl:apply-templates/>
-      </xsl:when>
-      <xsl:when test="$style = 'bold'">
-        <strong><xsl:apply-templates/></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'emphasis'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'illuminated'">
-        <strong><em><xsl:apply-templates/></em></strong>
-      </xsl:when>
-      <xsl:when test="$style = 'italic'">
-        <em><xsl:apply-templates/></em>
-      </xsl:when>
-      <xsl:when test="$style = 'line-through'">
-        <font class="strike"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="$style = 'normal'">
-        <font class="normal"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="$style = 'small-caps'">
-        <font class="small-caps"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:when test="$style = 'sub'">
-        <sub><xsl:apply-templates/></sub>
-      </xsl:when>
-      <xsl:when test="$style = 'super'">
-        <sup><xsl:apply-templates/></sup>
-      </xsl:when>
-      <xsl:when test="$style = 'underline'">
-        <u><xsl:apply-templates/></u>
-      </xsl:when>
-      <xsl:when test="$style = 'x-caps'">
-        <font class="caps"><xsl:apply-templates/></font>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:apply-templates/>
-      </xsl:otherwise>
-    </xsl:choose>
-  </xsl:template>
-
-  <!--
-    The following elements are actually TEI and there is some expectation
-    that these will make it into OSIS.
-  -->
-  <xsl:template match="superentry">
-    <!-- output each preverse element in turn -->
-    <xsl:for-each select="entry|entryFree">
-      <xsl:apply-templates/><br/><br/>
-    </xsl:for-each>
-  </xsl:template>
-
-  <xsl:template match="entry">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="entryFree">
-    <xsl:apply-templates/>
-  </xsl:template>
-
-  <xsl:template match="form">
-    <xsl:apply-templates/><br/>
-  </xsl:template>
-
-  <xsl:template match="orth">
-    <font class="orth"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="pron">
-    <font class="pron"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="etym">
-    <font class="etym"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="def">
-    <font class="def"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="usg">
-    <font class="usg"><xsl:apply-templates/></font>
-  </xsl:template>
-
-  <xsl:template match="@xml:lang">
-    <xsl:variable name="dir">
-      <xsl:if test="@xml:lang">
-        <xsl:call-template name="getDirection">
-         <xsl:with-param name="lang"><xsl:value-of select="@xml:lang"/></xsl:with-param>
-        </xsl:call-template>
-      </xsl:if>
-    </xsl:variable>
-    <xsl:if test="$dir">
-      <xsl:attribute name="dir">
-        <xsl:value-of select="$dir"/>
-      </xsl:attribute>
-    </xsl:if>
-  </xsl:template>
-
-  <!-- If the parent of the text is a verse then, we need to wrap in span. This applies
-  to any punctuation really, since all other words should be contained in a W  -->
-  <xsl:template match="text()">
-  		<xsl:choose>
-	  		<xsl:when test="name(..) = 'verse' and normalize-space(.) != ''"><span class="w"><span class="text"><xsl:value-of select="."/></span></span></xsl:when>
-	  		<xsl:when test="normalize-space(.) != ''"><xsl:value-of select="."/></xsl:when>
-  		</xsl:choose>
-  </xsl:template>
-
-
-  <xsl:template match="text()" mode="small-caps">
-  <xsl:value-of select="translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
-  </xsl:template>
-
-  <!--
-    The direction is deduced from the xml:lang attribute and is assumed to be meaningful for those elements.
-    Note: there is a bug that prevents dir=rtl from working.
-    see: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4296022 and 4866977
-  -->
-  <xsl:template name="getDirection">
-    <xsl:param name="lang"/>
-    <xsl:choose>
-      <xsl:when test="$lang = 'he' or $lang = 'ar' or $lang = 'fa' or $lang = 'ur' or $lang = 'syr'">
-        <xsl:value-of select="'rtl'"/>
-      </xsl:when>
-      <xsl:otherwise>
-        <xsl:value-of select="'ltr'"/>
-      </xsl:otherwise>
-    </xsl:choose>
-   </xsl:template>
-   
-	<xsl:template name="string-replace-all">
-	<xsl:param name="text" />
-	<xsl:param name="replace" />
-	<xsl:param name="by" />
-	<xsl:choose>
-		<xsl:when test="contains($text, $replace)">
-			<xsl:value-of select="substring-before($text,$replace)" />
-			<xsl:value-of select="$by" />
-			<xsl:call-template name="string-replace-all">
-				<xsl:with-param name="text" select="substring-after($text,$replace)" />
-				<xsl:with-param name="replace" select="$replace" />
-				<xsl:with-param name="by" select="$by" />
-			</xsl:call-template>
-		</xsl:when>
-		<xsl:otherwise>
-			<xsl:value-of select="$text" />
-		</xsl:otherwise>
-	</xsl:choose>
-</xsl:template>  
-</xsl:stylesheet>

Added: trunk/step/step-core/src/main/resources/step.core.properties
===================================================================
--- trunk/step/step-core/src/main/resources/step.core.properties	                        (rev 0)
+++ trunk/step/step-core/src/main/resources/step.core.properties	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,7 @@
+#list of installers in the format: host,package,catalog
+installer.1=www.crosswire.org,/ftpmirror/pub/sword/packages/rawzip,/ftpmirror/pub/sword/raw
+installer.2=ftp.bible.org,/sword/packages/rawzip,/sword/raw
+installer.3=www.crosswire.org,/ftpmirror/pub/sword/betapackages/rawzip,/ftpmirror/pub/sword/betaraw
+
+app.proxy.host=
+app.proxy.port=

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -2,14 +2,19 @@
 
 import static com.tyndalehouse.step.core.models.LookupOption.INTERLINEAR;
 
+import java.io.IOException;
 import java.io.StringReader;
 import java.util.ArrayList;
+import java.util.List;
 
 import org.crosswire.jsword.book.Book;
 import org.crosswire.jsword.book.BookData;
+import org.crosswire.jsword.book.BookException;
 import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.passage.NoSuchKeyException;
 import org.jdom.Document;
 import org.jdom.Element;
+import org.jdom.JDOMException;
 import org.jdom.input.SAXBuilder;
 import org.jdom.output.Format;
 import org.jdom.output.XMLOutputter;
@@ -28,32 +33,36 @@
  * 
  */
 public class JSwordServiceImplTest {
-    private final Logger logger = LoggerFactory.getLogger(getClass());
+    private static final Logger LOGGER = LoggerFactory.getLogger(JSwordServiceImplTest.class);
 
     /**
      * tests what happens when we select interlinear
      * 
-     * @throws Exception an uncaught exception
+     * @throws NoSuchKeyException uncaught exceptions
+     * @throws BookException uncaught exception
+     * @throws IOException uncaught exception
+     * @throws JDOMException uncaught exception
+     * 
      */
     @Test
-    public void testInterlinearTransformation() throws Exception {
+    public void testInterlinearTransformation() throws NoSuchKeyException, BookException, JDOMException, IOException {
         final Book currentBook = Books.installed().getBook("KJV");
         final BookData bookData = new BookData(currentBook, currentBook.getKey("Romans 1:1-3"));
         final Element osisFragment = bookData.getOsisFragment();
 
         final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
-        this.logger.debug(xmlOutputter.outputString(osisFragment));
+        LOGGER.debug(xmlOutputter.outputString(osisFragment));
 
         // do the test
-        final JSwordServiceImpl jsi = new JSwordServiceImpl();
-        final ArrayList<LookupOption> options = new ArrayList<LookupOption>();
+        final JSwordServiceImpl jsi = new JSwordServiceImpl(null);
+        final List<LookupOption> options = new ArrayList<LookupOption>();
         options.add(INTERLINEAR);
 
         final String osisText = jsi.getOsisText("KJV", "Romans 1:1-3", options, "KJV");
         final SAXBuilder sb = new SAXBuilder();
         final Document d = sb.build(new StringReader(osisText));
 
-        this.logger.debug("\n {}", xmlOutputter.outputString(d));
+        LOGGER.debug("\n {}", xmlOutputter.outputString(d));
         Assert.assertTrue(osisText.contains("span"));
 
     }
@@ -61,27 +70,30 @@
     /**
      * tests that the XSLT transformation is handled correctly
      * 
-     * @throws Exception uncaught exception
+     * @throws BookException uncaught exception
+     * @throws NoSuchKeyException uncaught exception
+     * @throws IOException uncaught exception
+     * @throws JDOMException uncaught exception
      */
     @Test
-    public void testXslTransformation() throws Exception {
+    public void testXslTransformation() throws BookException, NoSuchKeyException, JDOMException, IOException {
         final Book currentBook = Books.installed().getBook("KJV");
         final BookData bookData = new BookData(currentBook, currentBook.getKey("Romans 1:4"));
         final Element osisFragment = bookData.getOsisFragment();
 
         final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
-        this.logger.debug(xmlOutputter.outputString(osisFragment));
+        LOGGER.debug(xmlOutputter.outputString(osisFragment));
 
         // do the test
-        final JSwordServiceImpl jsi = new JSwordServiceImpl();
-        final ArrayList<LookupOption> options = new ArrayList<LookupOption>();
+        final JSwordServiceImpl jsi = new JSwordServiceImpl(null);
+        final List<LookupOption> options = new ArrayList<LookupOption>();
         options.add(LookupOption.STRONG_NUMBERS);
 
         final String osisText = jsi.getOsisText("KJV", "Romans 1:4", options, "");
         final SAXBuilder sb = new SAXBuilder();
         final Document d = sb.build(new StringReader(osisText));
 
-        this.logger.debug("\n {}", xmlOutputter.outputString(d));
+        LOGGER.debug("\n {}", xmlOutputter.outputString(d));
         Assert.assertTrue(osisText.contains("span"));
     }
 }

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImplTest.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/ModuleServiceImplTest.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -7,17 +7,22 @@
 
 import org.junit.Test;
 
+/**
+ * A simple test for the module service
+ * 
+ * @author Chris
+ * 
+ */
 public class ModuleServiceImplTest {
     /**
      * tests that different definitions references resolve to the right module by default
      */
     @Test
     public void testGetLookupModule() {
-        final ModuleServiceImpl msi = new ModuleServiceImpl();
         final Map<String, String> defaultModules = new HashMap<String, String>();
-        msi.setDefaultModuleLexicons(defaultModules);
+        defaultModules.put("key:", "module");
+        final ModuleServiceImpl msi = new ModuleServiceImpl(defaultModules, null);
 
-        defaultModules.put("key:", "module");
         assertEquals("module", msi.getLookupModule("key:H2929"));
     }
 }

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/utils/StringConversionUtilsTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/utils/StringConversionUtilsTest.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/utils/StringConversionUtilsTest.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -5,7 +5,16 @@
 
 import org.junit.Test;
 
+/**
+ * Tests the utility method for converting strings
+ * 
+ * @author Chris
+ * 
+ */
 public class StringConversionUtilsTest {
+    /**
+     * tests that getAnyKey returns the right portion of the string for different keys
+     */
     @Test
     public void testGetAnyKey() {
         assertEquals(getAnyKey("strong:H1"), "1");

Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -4,6 +4,12 @@
 
 import org.junit.Test;
 
+/**
+ * A simple test class to test to the provider
+ * 
+ * @author Chris
+ * 
+ */
 public class InterlinearProviderImplTest {
     /**
      * this checks that when keyed with strong, morph and verse number, we can retrieve the word. We should be able to

Modified: trunk/step/step-parent/pom.xml
===================================================================
--- trunk/step/step-parent/pom.xml	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-parent/pom.xml	2010-12-19 11:27:36 UTC (rev 195)
@@ -18,28 +18,33 @@
 
 		<derby.version>10.5.3.0_1</derby.version>
 		<junit.version>4.8.2</junit.version>
+
+		<!-- jsword dependencies -->
 		<jsword.version>1.6.1-SNAPSHOT</jsword.version>
-
-		<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
-		<jackson-mapper-asl.version>1.5.3</jackson-mapper-asl.version>
+		<jdom.version>1.1</jdom.version>
+		<javatar.version>2.5</javatar.version>
+		
+		<jackson-mapper-asl.version>1.6.2</jackson-mapper-asl.version>
 		<org.slf4j.version>1.6.1</org.slf4j.version>
 		<servlet-api.version>2.5</servlet-api.version>
 		<jsp-api.version>2.1</jsp-api.version>
 		<jstl.version>1.2</jstl.version>
 		<pjl-comp-filter.version>1.6.4</pjl-comp-filter.version>
+		<guice.version>2.1.8</guice.version>
+		<guice-servlet.version>2.9.1</guice-servlet.version>
+		<opencsv.version>2.1</opencsv.version>
+		<jetty.version>6.1.22</jetty.version>
 
 		<!-- Commons -->
 		<commons-beanutils.version>1.8.3</commons-beanutils.version>
 		<commons-lang.version>2.5</commons-lang.version>
-
-
+		<commons-collections.version>3.2.1</commons-collections.version>
 		<commons-configuration.version>1.6</commons-configuration.version>
-
 		<commons-dbcp.version>1.3</commons-dbcp.version>
 		<commons-io.version>1.4</commons-io.version>
 		<commons-dbutils.version>1.3</commons-dbutils.version>
-		<jmock.version>2.5.1</jmock.version>
-		<opencsv.version>2.1</opencsv.version>
+
+		<!-- testing dependencies -->
 		<mockito.version>1.8.5</mockito.version>
 	</properties>
 
@@ -56,7 +61,6 @@
 				<artifactId>step-core</artifactId>
 				<version>${project.version}</version>
 			</dependency>
-
 			<dependency>
 				<groupId>org.crosswire</groupId>
 				<artifactId>jsword</artifactId>
@@ -67,28 +71,17 @@
 				<artifactId>jsword-common</artifactId>
 				<version>${jsword.version}</version>
 			</dependency>
-
-			<!-- Spring dependencies -->
 			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-context</artifactId>
-				<version>${org.springframework.version}</version>
-				<exclusions>
-					<!-- Exclude Commons Logging in favor of SLF4j -->
-					<exclusion>
-						<groupId>commons-logging</groupId>
-						<artifactId>commons-logging</artifactId>
-					</exclusion>
-				</exclusions>
-
+			    <groupId>javatar</groupId>
+			    <artifactId>javatar</artifactId>
+			    <version>${javatar.version}</version>
 			</dependency>
 			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-webmvc</artifactId>
-				<version>${org.springframework.version}</version>
+				<groupId>org.jdom</groupId>
+				<artifactId>jdom</artifactId>
+				<version>${jdom.version}</version>
 			</dependency>
 
-
 			<dependency>
 				<groupId>org.codehaus.jackson</groupId>
 				<artifactId>jackson-mapper-asl</artifactId>
@@ -138,7 +131,35 @@
 			    <version>${pjl-comp-filter.version}</version>
 			</dependency>
 
+			<!-- TODO build against google released artifacts -->
 			<dependency>
+				<groupId>com.jolira</groupId>
+				<artifactId>guice</artifactId>
+				<version>${guice.version}</version>
+			</dependency>
+			
+			<dependency>
+			    <groupId>org.sonatype.sisu.inject</groupId>
+			    <artifactId>guice-servlet</artifactId>
+			    <version>${guice-servlet.version}</version>
+			</dependency>
+
+			<dependency>
+				<groupId>org.restlet.jee</groupId>
+				<artifactId>org.restlet</artifactId>
+				<version>${restlet.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.restlet.jee</groupId>
+				<artifactId>org.restlet.ext.servlet</artifactId>
+				<version>${restlet.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.restlet.jee</groupId>
+				<artifactId>org.restlet.ext.json</artifactId>
+				<version>${restlet.version}</version>
+			</dependency>
+			<dependency>
 				<groupId>commons-beanutils</groupId>
 				<artifactId>commons-beanutils</artifactId>
 				<version>${commons-beanutils.version}</version>
@@ -150,12 +171,13 @@
 				<version>${commons-lang.version}</version>
 			</dependency>
 
-
-			<!-- probably unnecessary for now <dependency> <groupId>org.tuckey</groupId> 
-				<artifactId>urlrewritefilter</artifactId> <version>3.1.0</version> </dependency> -->
-
-
 			<dependency>
+				<groupId>commons-collections</groupId>
+				<artifactId>commons-collections</artifactId>
+				<version>${commons-collections.version}</version>
+			</dependency>
+			
+			<dependency>
 				<groupId>commons-dbcp</groupId>
 				<artifactId>commons-dbcp</artifactId>
 				<version>${commons-dbcp.version}</version>
@@ -182,20 +204,6 @@
 			</dependency>
 
 			<dependency>
-				<groupId>org.jmock</groupId>
-				<artifactId>jmock</artifactId>
-				<version>${jmock.version}</version>
-				<scope>test</scope>
-			</dependency>
-
-			<dependency>
-				<groupId>org.jmock</groupId>
-				<artifactId>jmock-junit4</artifactId>
-				<version>${jmock.version}</version>
-				<scope>test</scope>
-			</dependency>
-
-			<dependency>
 				<groupId>org.apache.derby</groupId>
 				<artifactId>derbyclient</artifactId>
 				<version>${derby.version}</version>
@@ -222,6 +230,12 @@
 			</dependency>
 
 			<dependency>
+				<groupId>org.mortbay.jetty</groupId>
+				<artifactId>jetty</artifactId>
+				<version>${jetty.version}</version>
+			</dependency>
+			
+			<dependency>
 				<groupId>junit</groupId>
 				<artifactId>junit</artifactId>
 				<version>${junit.version}</version>
@@ -251,6 +265,8 @@
 					<version>2.5</version>
 					<configuration>
 						<junitArtifactName>junit:junit-dep</junitArtifactName>
+						<parallel>classes</parallel>
+						<threadCount>4</threadCount>
 					</configuration>
 				</plugin>
 
@@ -280,18 +296,19 @@
 						<wtpversion>2.0</wtpversion>
 
 						<additionalProjectnatures>
-							<projectnature>com.google.gwt.eclipse.core.gwtNature</projectnature>
-							<projectnature>com.google.gdt.eclipse.core.webAppNature</projectnature>
 							<projectnature>net.sourceforge.pmd.eclipse.plugin.pmdNature</projectnature>
 							<projectnature>net.sf.eclipsecs.core.CheckstyleNature</projectnature>
 							<projectnature>edu.umd.cs.findbugs.plugin.eclipse.findbugsNature</projectnature>
+							<projectnature>org.maven.ide.eclipse.maven2Nature</projectnature>
+							
 						</additionalProjectnatures>
 						<additionalBuildcommands>
 							<buildcommand>net.sourceforge.pmd.eclipse.plugin.pmdBuilder</buildcommand>
 							<buildcommand>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</buildcommand>
 							<buildcommand>net.sf.eclipsecs.core.CheckstyleBuilder</buildcommand>
+							<buildcommand>org.maven.ide.eclipse.maven2Builder</buildcommand>
 						</additionalBuildcommands>
-
+		
 						<additionalConfig>
 							<file>
 								<name>.settings/org.eclipse.jdt.core.prefs</name>
@@ -311,6 +328,10 @@
 								<location>/checkstyle/checkstyle.xml</location>
 							</file>
 							<file>
+								<name>.checkstyle.config.test.xml</name>
+								<location>/checkstyle/checkstyle.test.xml</location>
+							</file>
+							<file>
 								<name>.pmd</name>
 								<location>/eclipse/pmd.xml</location>
 							</file>
@@ -318,7 +339,10 @@
 								<name>.fbprefs</name>
 								<location>/eclipse/.fbprefs</location>
 							</file>
-
+							<file>
+								<name>.LICENSE.txt</name>
+								<location>/checkstyle/license.txt</location>
+							</file>
 						</additionalConfig>
 					</configuration>
 					<dependencies>

Modified: trunk/step/step-server/pom.xml
===================================================================
--- trunk/step/step-server/pom.xml	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-server/pom.xml	2010-12-19 11:27:36 UTC (rev 195)
@@ -8,7 +8,7 @@
 	</parent>
 
 	<modelVersion>4.0.0</modelVersion>
-	<groupId>com.tyndalehouse</groupId>
+	<groupId>com.tyndalehouse.step</groupId>
 	<artifactId>step-server</artifactId>
 	<packaging>jar</packaging>
 	<name>STEP :: Server wrapper for local execution</name>
@@ -17,7 +17,35 @@
 		<dependency>
 			<groupId>org.mortbay.jetty</groupId>
 			<artifactId>jetty</artifactId>
-			<version>6.1.22</version>
+			<version>${jetty.version}</version>
 		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+
 	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+					<archive>
+						<manifest>
+							<mainClass>com.tyndalehouse.step.server.StepServer</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
 </project>

Modified: trunk/step/step-server/src/main/java/com/tyndalehouse/step/server/StepServer.java
===================================================================
--- trunk/step/step-server/src/main/java/com/tyndalehouse/step/server/StepServer.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-server/src/main/java/com/tyndalehouse/step/server/StepServer.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,50 +1,80 @@
 package com.tyndalehouse.step.server;
 
-//import java.awt.Desktop;
 import java.awt.Desktop;
+import java.io.IOException;
 import java.net.URI;
 import java.net.URL;
 
 import org.mortbay.jetty.Server;
 import org.mortbay.jetty.webapp.WebAppContext;
 import org.mortbay.xml.XmlConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
 
-public class StepServer {
+/**
+ * the main class that kicks off the application
+ * 
+ * @author Chris
+ * 
+ */
+public final class StepServer {
+    private static final Logger LOGGER = LoggerFactory.getLogger(StepServer.class);
 
     /**
+     * hiding implementation
+     */
+    private StepServer() {
+        // hiding implementation
+    }
+
+    /**
      * creates and configures the Jetty server
      * 
      * @return the Server object if required to make modifications
-     * @throws Exception any uncaught exceptions that should be logged before exiting
      */
-    private Server start() throws Exception {
+    private Server start() {
         final Server jetty = new Server();
-        final URL jettyConfig = StepServer.class.getClassLoader().getResource("jetty.xml");
-        final URL warURL = StepServer.class.getClassLoader().getResource("war");
+        final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+        final URL jettyConfig = currentClassLoader.getResource("jetty.xml");
+        final URL warURL = currentClassLoader.getResource("war");
 
         // configure jetty
-        final XmlConfiguration configuration = new XmlConfiguration(jettyConfig);
-        configuration.configure(jetty);
+        XmlConfiguration configuration;
+        try {
+            configuration = new XmlConfiguration(jettyConfig);
+            configuration.configure(jetty);
 
-        // configure our web application
-        jetty.setHandler(new WebAppContext(warURL.toExternalForm(), "/step-web"));
+            // configure our web application
+            jetty.setHandler(new WebAppContext(warURL.toExternalForm(), "/step-web"));
 
-        // start the server
-        jetty.start();
+            // start the server
+            jetty.start();
+        } catch (final SAXException e) {
+            LOGGER.error(e.getMessage(), e);
+        } catch (final IOException e) {
+            LOGGER.error(e.getMessage(), e);
+            // CHECKSTYLE:OFF
+        } catch (final Exception e) {
+            // CHECKSTYLE:ON
+            LOGGER.error(e.getMessage(), e);
+        }
         return jetty;
     }
 
     /**
-     * @param args
+     * @param args a list of unused arguments on the command line
      */
+    // CHECKSTYLE:OFF
     public static void main(final String[] args) {
         try {
-            // TODO setup logger somewhere!
             final StepServer ms = new StepServer();
             ms.start();
             Desktop.getDesktop().browse(new URI("http://localhost:8080/step-web"));
+
         } catch (final Exception e) {
-            e.printStackTrace();
+            LOGGER.debug(e.getMessage(), e);
         }
     }
+    // CHECKSTYLE:ON
 }

Modified: trunk/step/step-web/pom.xml
===================================================================
--- trunk/step/step-web/pom.xml	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/pom.xml	2010-12-19 11:27:36 UTC (rev 195)
@@ -19,16 +19,8 @@
 		<dependency>
 			<groupId>com.tyndalehouse.step</groupId>
 			<artifactId>step-core</artifactId>
-		</dependency>	
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-context</artifactId>
 		</dependency>
 		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-webmvc</artifactId>
-		</dependency>
-		<dependency>
 			<groupId>org.codehaus.jackson</groupId>
 			<artifactId>jackson-mapper-asl</artifactId>
 		</dependency>
@@ -65,17 +57,40 @@
 			<artifactId>jstl</artifactId>
 		</dependency>
 		<dependency>
-		    <groupId>net.sourceforge.pjl-comp-filter</groupId>
-		    <artifactId>pjl-comp-filter</artifactId>
+			<groupId>net.sourceforge.pjl-comp-filter</groupId>
+			<artifactId>pjl-comp-filter</artifactId>
 		</dependency>
-	
+
 		<dependency>
+			<groupId>com.jolira</groupId>
+			<artifactId>guice</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.sonatype.sisu.inject</groupId>
+			<artifactId>guice-servlet</artifactId>
+		</dependency>
+
+		<!-- test dependencies -->
+		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>
 			<scope>test</scope>
 		</dependency>
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-core</artifactId>
+		</dependency>
+
+
+		<!-- transitive dependencies not picked up by jsword -->
+		<dependency>
+			<groupId>javatar</groupId>
+			<artifactId>javatar</artifactId>
+			<version>${javatar.version}</version>
+		</dependency>
+		
 	</dependencies>
-	
+
 	<build>
 		<finalName>step-web</finalName>
 	</build>

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/guice/StepServletConfig.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,27 @@
+package com.tyndalehouse.step.guice;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceServletContextListener;
+import com.google.inject.servlet.ServletModule;
+import com.tyndalehouse.step.core.guice.StepCoreModule;
+import com.tyndalehouse.step.rest.controllers.FrontController;
+
+/**
+ * Configures the listener for the web app to return the injector used to configure the whole of the application
+ * 
+ * @author Chris
+ * 
+ */
+public class StepServletConfig extends GuiceServletContextListener {
+
+    @Override
+    protected Injector getInjector() {
+        return Guice.createInjector(new StepCoreModule(), new ServletModule() {
+            @Override
+            protected void configureServlets() {
+                serve("/rest/*").with(FrontController.class);
+            }
+        });
+    }
+}

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,24 +1,22 @@
 package com.tyndalehouse.step.rest;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-public class JsonExceptionResolver implements HandlerExceptionResolver {
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
-    public ModelAndView resolveException(final HttpServletRequest request, final HttpServletResponse response,
-            final Object handler, final Exception exception) {
-
-        this.logger.error(exception.getMessage(), exception);
-
-        final ModelAndView mav = new ModelAndView();
-        mav.setViewName("MappingJacksonJsonView");
-        mav.addObject("error", exception.getMessage());
-        return mav;
-    }
+/**
+ * A JSon exception resolver
+ * 
+ * @author Chris
+ * 
+ */
+public class JsonExceptionResolver /* implements HandlerExceptionResolver */{
+    // private final Logger logger = LoggerFactory.getLogger(getClass());
+    //
+    // public ModelAndView resolveException(final HttpServletRequest request, final HttpServletResponse response,
+    // final Object handler, final Exception exception) {
+    //
+    // this.logger.error(exception.getMessage(), exception);
+    //
+    // final ModelAndView mav = new ModelAndView();
+    // mav.setViewName("MappingJacksonJsonView");
+    // mav.addObject("error", exception.getMessage());
+    // return mav;
+    // }
 }

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -8,35 +8,45 @@
 import org.apache.commons.lang.Validate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
 
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 import com.tyndalehouse.step.core.models.BibleVersion;
 import com.tyndalehouse.step.core.models.EnrichedLookupOption;
 import com.tyndalehouse.step.core.models.LookupOption;
 import com.tyndalehouse.step.core.service.BibleInformationService;
 import com.tyndalehouse.step.rest.wrappers.HtmlWrapper;
 
- at RequestMapping(value = "/bible", method = RequestMethod.GET)
- at Controller
+/**
+ * The controller for retrieving information on the bible or texts from the bible
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
 public class BibleController {
-    @Autowired
-    private BibleInformationService bibleInformation;
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+    private static final long serialVersionUID = -5176839737814243641L;
+    private static final Logger LOGGER = LoggerFactory.getLogger(BibleController.class);
+    private final BibleInformationService bibleInformation;
 
     /**
+     * creates the controller giving access to bible information
+     * 
+     * @param bibleInformation the service allowing access to biblical material
+     */
+    @Inject
+    public BibleController(final BibleInformationService bibleInformation) {
+        this.bibleInformation = bibleInformation;
+        LOGGER.debug("Created Bible Controller");
+    }
+
+    /**
      * a REST method that returns version of the Bible that are available
      * 
      * @return all versions of modules that are considered to be Bibles.
      */
-    @RequestMapping(value = "/versions")
-    public @ResponseBody
-    List<BibleVersion> getBibleVersions() {
-        return this.bibleInformation.getBibleVersions();
+    public List<BibleVersion> getBibleVersions() {
+        return this.bibleInformation.getAvailableBibleVersions();
     }
 
     /**
@@ -46,9 +56,7 @@
      * @param reference the reference to lookup
      * @return the text to be displayed, formatted as HTML
      */
-    @RequestMapping(value = "/text/{version}/{reference}")
-    public @ResponseBody
-    HtmlWrapper getBibleText(@PathVariable final String version, @PathVariable final String reference) {
+    public HtmlWrapper getBibleText(final String version, final String reference) {
         return getBibleText(version, reference, null, null);
     }
 
@@ -57,12 +65,10 @@
      * 
      * @param version the initials identifying the version
      * @param reference the reference to lookup
+     * @param options the list of options to be passed through and affect the retrieval process
      * @return the text to be displayed, formatted as HTML
      */
-    @RequestMapping(value = "/text/{version}/{reference}/{options}")
-    public @ResponseBody
-    HtmlWrapper getBibleText(@PathVariable final String version, @PathVariable final String reference,
-            @PathVariable final String options) {
+    public HtmlWrapper getBibleText(final String version, final String reference, final String options) {
         return getBibleText(version, reference, options, null);
     }
 
@@ -72,12 +78,11 @@
      * @param version the initials identifying the version
      * @param reference the reference to lookup
      * @param options a list of options to be passed in
+     * @param interlinearVersion the interlinear version if provided adds lines under the text
      * @return the text to be displayed, formatted as HTML
      */
-    @RequestMapping(value = "/text/{version}/{reference}/{options}/{interlinearVersion}")
-    public @ResponseBody
-    HtmlWrapper getBibleText(@PathVariable final String version, @PathVariable final String reference,
-            @PathVariable final String options, @PathVariable final String interlinearVersion) {
+    public HtmlWrapper getBibleText(final String version, final String reference, final String options,
+            final String interlinearVersion) {
         Validate.notEmpty(version, "You need to provide a version");
         Validate.notEmpty(reference, "You need to provide a reference");
 
@@ -100,18 +105,19 @@
     /**
      * a REST method that returns version of the Bible that are available
      * 
+     * @param version the version initials or full version name to retrieve the versions for
      * @return all versions of modules that are considered to be Bibles.
      */
-    @RequestMapping(value = "/features/{version}")
-    public @ResponseBody
-    List<LookupOption> getBibleVersions(@PathVariable final String version) {
+    public List<LookupOption> getFeatures(final String version) {
         return this.bibleInformation.getFeaturesForVersion(version);
     }
 
-    @RequestMapping(value = "/features-all")
-    public @ResponseBody
-    List<EnrichedLookupOption> getAllFeatures() {
-        // Use EH Cache to cache this
+    /**
+     * retrieves the list of features currently supported by the application
+     * 
+     * @return a list of features currently supported by the application
+     */
+    public List<EnrichedLookupOption> getAllFeatures() {
         return this.bibleInformation.getAllFeatures();
     }
 }

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,293 @@
+package com.tyndalehouse.step.rest.controllers;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.core.exceptions.StepInternalException;
+
+/**
+ * The FrontController acts like a minimal REST server. The paths are resolved as follows:
+ * 
+ * /step-web/rest/controllerName/methodName/arg1/arg2/arg3
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
+public class FrontController extends HttpServlet {
+    private static final String UTF_8_ENCODING = "UTF-8";
+    private static final Logger LOGGER = LoggerFactory.getLogger(FrontController.class);
+    private static final char PACKAGE_SEPARATOR = '.';
+    private static final long serialVersionUID = 7898656504631346047L;
+    private static final String CONTROLLER_SUFFIX = "Controller";
+    private final Map<String, String> contextPath = new HashMap<String, String>();
+    private final transient Injector guiceInjector;
+    // TODO but also check threadsafety and whether we should share this object
+    private final transient ObjectMapper jsonMapper = new ObjectMapper();
+    private final Map<String, Method> methodNames = new HashMap<String, Method>();
+    private final Map<String, Object> controllers = new HashMap<String, Object>();
+
+    /**
+     * creates the front controller which will dispatch all the requests
+     * 
+     * @param guiceInjector the injector used to call the relevant controllers
+     */
+    @Inject
+    public FrontController(final Injector guiceInjector) {
+        this.guiceInjector = guiceInjector;
+    }
+
+    @Override
+    protected void doGet(final HttpServletRequest req, final HttpServletResponse response) {
+        // fast string manipulation... (?)
+        final String requestURI = req.getRequestURI();
+        LOGGER.debug("Processing {}", requestURI);
+
+        final int requestStart = getPath(req).length() + 1;
+        final int endOfControllerName = requestURI.indexOf('/', requestStart);
+        final int startOfMethodName = endOfControllerName + 1;
+        final String controllerName = requestURI.substring(requestStart, endOfControllerName);
+        final String methodName = requestURI.substring(startOfMethodName,
+                requestURI.indexOf('/', startOfMethodName));
+        final int endOfMethodName = startOfMethodName + methodName.length();
+
+        LOGGER.debug("Request parsed as controller: [{}], method [{}]", controllerName, methodName);
+
+        // controller instance on which to call a method
+        final Object controllerInstance = getController(controllerName);
+
+        // some arguments to be passsed through
+        final Object[] args = getArgs(requestURI, endOfMethodName + 1);
+
+        // resolve method
+        final Method controllerMethod = getControllerMethod(methodName, controllerInstance, args);
+
+        try {
+            // invoke the three together
+            final Object returnVal = controllerMethod.invoke(controllerInstance, args);
+            final String jsonReturnValue = this.jsonMapper.writeValueAsString(returnVal);
+
+            final byte[] jsonEncoded = jsonReturnValue.getBytes(UTF_8_ENCODING);
+
+            // put results in cache if method is annotated. We don't need to do that
+            // afterwards...
+            setupHeaders(response, jsonEncoded.length);
+            response.getOutputStream().write(jsonEncoded);
+            // response.getOutputStream().flush();
+            // response.getOutputStream().close();
+
+            // perhaps we want to cache things...
+            // TODO
+
+        } catch (final StepInternalException e) {
+            // TODO handle this slightly differently?
+            doError(e);
+        } catch (final NoSuchMethodError e) {
+            doError(e);
+        } catch (final IllegalAccessException e) {
+            doError(e);
+        } catch (final InvocationTargetException e) {
+            doError(e);
+        } catch (final JsonGenerationException e) {
+            doError(e);
+        } catch (final JsonMappingException e) {
+            doError(e);
+        } catch (final IOException e) {
+            doError(e);
+        }
+    }
+
+    /**
+     * sets up the headers and the length of the message
+     * 
+     * @param response the response
+     * @param length the length of the message
+     */
+    private void setupHeaders(final HttpServletResponse response, final int length) {
+        // we ensure that headers are set up appropriately
+        response.addDateHeader("Date", System.currentTimeMillis());
+        response.setCharacterEncoding(UTF_8_ENCODING);
+        response.setContentType("application/json");
+        response.setContentLength(length);
+    }
+
+    /**
+     * deals with an error whilst executing the request
+     * 
+     * @param e the exception
+     */
+    private void doError(final Throwable e) {
+        LOGGER.error(e.getMessage(), e);
+
+        // TODO deal with error here:
+
+    }
+
+    /**
+     * Retrieves a controller, either from the cache, or from Guice
+     * 
+     * @param controllerName the name of the controller (used as the key for the cache)
+     * @return the controller object
+     */
+    Object getController(final String controllerName) {
+        Object controllerInstance = this.controllers.get(controllerName);
+
+        // if retrieving yields null, get controller from Guice, and put in cache
+        if (controllerInstance == null) {
+            // make up the full class name
+            final String packageName = getClass().getPackage().getName();
+            final StringBuilder className = new StringBuilder(packageName.length() + controllerName.length()
+                    + CONTROLLER_SUFFIX.length() + 1);
+
+            className.append(packageName);
+            className.append(PACKAGE_SEPARATOR);
+            className.append(Character.toUpperCase(controllerName.charAt(0)));
+            className.append(controllerName.substring(1));
+            className.append(CONTROLLER_SUFFIX);
+
+            try {
+                final Class<?> controllerClass = Class.forName(className.toString());
+                controllerInstance = this.guiceInjector.getInstance(controllerClass);
+
+                // we use the controller name as it came in to key the map
+                this.controllers.put(controllerName, controllerInstance);
+            } catch (final ClassNotFoundException e) {
+                throw new StepInternalException("Unable to find a controller for " + className, e);
+            }
+        }
+        return controllerInstance;
+    }
+
+    /**
+     * Returns the method to be invoked upon the controller
+     * 
+     * @param methodName the method name
+     * @param controllerInstance the instance of the controller
+     * @param args the list of arguments, required to resolve the correct method if they have arguments
+     * @return the method to be invoked
+     */
+    Method getControllerMethod(final String methodName, final Object controllerInstance, final Object[] args) {
+        final Class<? extends Object> controllerClass = controllerInstance.getClass();
+
+        // try cache first
+        final String cacheKey = getCacheKey(controllerClass.getName(), methodName, args.length);
+
+        // retrieve method from cache, or put in cache if not there
+        Method controllerMethod = this.methodNames.get(cacheKey);
+        if (controllerMethod == null) {
+            // resolve method
+            try {
+                controllerMethod = controllerClass.getMethod(methodName, getClasses(args));
+
+                // put method in cache
+                this.methodNames.put(cacheKey, controllerMethod);
+            } catch (final NoSuchMethodException e) {
+                throw new StepInternalException(e.getMessage(), e);
+            }
+        }
+        return controllerMethod;
+    }
+
+    /**
+     * @param args a number of arguments
+     * @return an array of classes matching the list of arguments passed in
+     */
+    Class<?>[] getClasses(final Object[] args) {
+        if (args == null) {
+            return new Class<?>[0];
+        }
+
+        final Class<?>[] classes = new Class<?>[args.length];
+
+        for (int ii = 0; ii < classes.length; ii++) {
+            classes[ii] = args[ii].getClass();
+        }
+
+        return classes;
+    }
+
+    /**
+     * returns the cache key to resolve from the cache
+     * 
+     * @param controllerName the controller name
+     * @param methodName the method name
+     * @param numArgs the number of arguments affects which method is returned
+     * @return the key to the method as expected in the cache.
+     */
+    String getCacheKey(final String controllerName, final String methodName, final int numArgs) {
+        final StringBuilder cacheKeyBuffer = new StringBuilder(controllerName.length() + methodName.length());
+        cacheKeyBuffer.append(controllerName);
+        cacheKeyBuffer.append(methodName);
+        cacheKeyBuffer.append(numArgs);
+        return cacheKeyBuffer.toString();
+    }
+
+    /**
+     * gets the arguments out of the requestURI String
+     * 
+     * @param requestURI the request URI string
+     * @param parameterStart the location at which the parameters start
+     * @return a list of arguments
+     */
+    String[] getArgs(final String requestURI, final int parameterStart) {
+        final List<String> arguments = new ArrayList<String>();
+        int argStart = parameterStart;
+        int nextArgStop = requestURI.indexOf('/', argStart);
+        try {
+            while (nextArgStop != -1) {
+                arguments.add(URLDecoder.decode(requestURI.substring(argStart, nextArgStop), UTF_8_ENCODING));
+                argStart = nextArgStop + 1;
+                nextArgStop = requestURI.indexOf('/', argStart);
+            }
+        } catch (final UnsupportedEncodingException e) {
+            throw new StepInternalException(e.getMessage(), e);
+        }
+
+        // add the last argument
+        if (argStart < requestURI.length()) {
+            try {
+                arguments.add(URLDecoder.decode(requestURI.substring(argStart), UTF_8_ENCODING));
+            } catch (final UnsupportedEncodingException e) {
+                throw new StepInternalException("Unable to decode last argument", e);
+            }
+        }
+        return arguments.toArray(new String[arguments.size()]);
+    }
+
+    /**
+     * Retrieves the path from the request
+     * 
+     * @param req the request
+     * @return the concatenated request
+     */
+    String getPath(final HttpServletRequest req) {
+        final String servletPath = req.getServletPath();
+        String path = this.contextPath.get(servletPath);
+
+        if (path == null) {
+            path = super.getServletContext().getContextPath() + servletPath;
+            this.contextPath.put(servletPath, path);
+        }
+        return path;
+    }
+}

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/ModuleController.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,33 +1,57 @@
 package com.tyndalehouse.step.rest.controllers;
 
+import java.util.List;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
 
+import com.google.inject.Inject;
+import com.tyndalehouse.step.core.models.BibleVersion;
 import com.tyndalehouse.step.core.service.ModuleService;
 
- at RequestMapping(value = "/module", method = RequestMethod.GET)
- at Controller
+/**
+ * The Module Controller servicing requests for module information
+ */
 public class ModuleController {
-    @Autowired
-    private ModuleService moduleDefintions;
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+    private static final Logger LOGGER = LoggerFactory.getLogger(ModuleController.class);
+    private final ModuleService moduleDefintions;
 
     /**
+     * sets up the controller to access module information
+     * 
+     * @param moduleDefintions the service allowing access to module information
+     */
+    @Inject
+    public ModuleController(final ModuleService moduleDefintions) {
+        this.moduleDefintions = moduleDefintions;
+    }
+
+    /**
      * a REST method that returns version of the Bible that are available
      * 
-     * @param reference a reference for a module to lookup
      * @return all versions of modules that are considered to be Bibles.
      */
-    @RequestMapping(value = "/definitions/{reference}")
-    public @ResponseBody
-    String getDefinition(@PathVariable final String reference) {
-        this.logger.debug("Getting definition for {}", reference);
+    public List<BibleVersion> getAllModules() {
+        return this.moduleDefintions.getAvailableModules();
+    }
+
+    /**
+     * a REST method that returns version of the Bible that are not yet installed
+     * 
+     * @return all versions of modules that are considered to be modules and usable by STEP.
+     */
+    public List<BibleVersion> getAllInstallableModules() {
+        return this.moduleDefintions.getAllInstallableModules();
+    }
+
+    /**
+     * a REST method that returns all the definitions for a particular key
+     * 
+     * @param reference a reference for a module to lookup
+     * @return the definition(s) that can be resolved from the reference provided
+     */
+    public String getDefinition(final String reference) {
+        LOGGER.debug("Getting definition for {}", reference);
         return this.moduleDefintions.getDefinition(reference).getExplanation();
     }
 }

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/SetupController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/SetupController.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/SetupController.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,63 @@
+package com.tyndalehouse.step.rest.controllers;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.core.service.BibleInformationService;
+
+/**
+ * The controller that will deal with any requests changing the behaviour of the application
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
+public class SetupController {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SetupController.class);
+    private final BibleInformationService bibleInformation;
+
+    /**
+     * creates the controller
+     * 
+     * @param bibleInformationService the service that allows access to biblical material
+     */
+    @Inject
+    public SetupController(final BibleInformationService bibleInformationService) {
+        this.bibleInformation = bibleInformationService;
+    }
+
+    /**
+     * a REST method to retrieve events between two dates The arrays match in index, and go by three (timebandId, from,
+     * to), (timebandId, from, to), ...
+     * 
+     * @return true if the software reckons this is the first time
+     */
+    // @RequestMapping("/isFirstTime")
+    public boolean isFirstTime() {
+        LOGGER.debug("Checking whether this is the first time the software is being run");
+        return !this.bibleInformation.hasCoreModules();
+    }
+
+    /**
+     * Installing default modules
+     * 
+     */
+    // @RequestMapping("/install/defaultModules")
+    public void installDefaultModules() {
+        LOGGER.debug("Installing default modules");
+        this.bibleInformation.installDefaultModules();
+    }
+
+    /**
+     * Installing default modules
+     * 
+     * @param reference the initials of the bible to install
+     */
+    // @RequestMapping("/install/book/{reference}")
+    public void installBible(final String reference) {
+        LOGGER.debug("Installing module {}", reference);
+        this.bibleInformation.installModules(reference);
+    }
+}

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,48 @@
+package com.tyndalehouse.step.rest.controllers;
+
+import java.util.Date;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Singleton;
+
+/**
+ * The timeline controller retrieves information about past events
+ * 
+ * @author Chris
+ * 
+ */
+ at Singleton
+public class TimelineController {
+    private static final Logger LOGGER = LoggerFactory.getLogger(TimelineController.class);
+
+    /**
+     * a REST method to retrieve events between two dates The arrays match in index, and go by three (timebandId, from,
+     * to), (timebandId, from, to), ...
+     * 
+     * @param timebandId the timeband ids
+     * @param from the from dates
+     * @param to the to dates
+     * @return all versions of modules that are considered to be Bibles. TODO work out UK date format mappings
+     */
+    // @RequestMapping("/events")
+    public String getEvents(final String[] timebandId, final Date from, final Date to) {
+        LOGGER.debug("Retrieving events between [{}] and [{}]", from, to);
+        return timebandId[0];
+    }
+
+    /**
+     * Retrieves events based on a biblical reference. This method also needs to return an origin and a scale for the
+     * timeline to be displayed properly as it might well be that the UI has carried out a different search
+     * 
+     * @param bibleReference the bible reference that might have a set of events related to it
+     * @return a list of events to be shown on a timeline, including the origin of the timeline and the scale of the
+     *         timeline
+     */
+    // @RequestMapping("/eventsFromReference")
+    public String getEventsFromReference(final String bibleReference) {
+
+        return null;
+    }
+}

Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cached.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cached.java	                        (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/framework/Cached.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,22 @@
+package com.tyndalehouse.step.rest.framework;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * This indicates that the REST-like call can be cached by the server
+ * 
+ * @author Chris
+ * 
+ */
+ at Target(METHOD)
+ at Retention(RUNTIME)
+public @interface Cached {
+    /** true to indicate that the results from the method can be cached */
+    // CHECKSTYLE:OFF
+    boolean value = false;
+    // CHECKSTYLE:ON
+}

Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -1,12 +1,26 @@
 package com.tyndalehouse.step.rest.wrappers;
 
+/**
+ * A simple wrapper around a string for returning as a JSON-mapped object
+ * 
+ * @author Chris
+ * 
+ */
 public class HtmlWrapper {
-    final String value;
+    private final String value;
 
+    /**
+     * the value to be wrapped
+     * 
+     * @param value the value to be wrapped around
+     */
     public HtmlWrapper(final String value) {
         this.value = value;
     }
 
+    /**
+     * @return the value to be returned
+     */
     public String getValue() {
         return this.value;
     }

Modified: trunk/step/step-web/src/main/webapp/WEB-INF/web.xml
===================================================================
--- trunk/step/step-web/src/main/webapp/WEB-INF/web.xml	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/WEB-INF/web.xml	2010-12-19 11:27:36 UTC (rev 195)
@@ -5,56 +5,30 @@
 <web-app>
 	<display-name>STEP :: Scripture Tools for Every Pastor</display-name>
 
-	<context-param>
-		<param-name>contextConfigLocation</param-name>
-		<param-value>classpath*:com/tyndalehouse/step/**/config/*-applicationContext.xml</param-value>
-	</context-param>
-
 	<filter>
-		<filter-name>requestEncodingFilter</filter-name>
-		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
-		<init-param>
-			<param-name>encoding</param-name>
-			<param-value>UTF-8</param-value>
-		</init-param>
-		<init-param>
-			<param-name>forceEncoding</param-name>
-			<param-value>true</param-value>
-		</init-param>
+		<filter-name>guiceFilter</filter-name>
+		<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
 	</filter>
+
 	<filter>
 		<filter-name>CompressingFilter</filter-name>
 		<filter-class>com.planetj.servlet.filter.compression.CompressingFilter</filter-class>
 	</filter>
 
-	<!-- don't need to do all the time TODO -->
 	<filter-mapping>
-		<filter-name>requestEncodingFilter</filter-name>
+		<filter-name>CompressingFilter</filter-name>
 		<url-pattern>/*</url-pattern>
 	</filter-mapping>
+
 	<filter-mapping>
-		<filter-name>CompressingFilter</filter-name>
+		<filter-name>guiceFilter</filter-name>
 		<url-pattern>/*</url-pattern>
 	</filter-mapping>
+
 	<listener>
-		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+		<listener-class>com.tyndalehouse.step.guice.StepServletConfig</listener-class>
 	</listener>
 
-
-	<!-- Spring context Configuration Begins -->
-
-	<servlet>
-		<servlet-name>step-rest</servlet-name>
-		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-
-	<servlet-mapping>
-		<servlet-name>step-rest</servlet-name>
-		<url-pattern>/rest/*</url-pattern>
-	</servlet-mapping>
-
-
 	<welcome-file-list>
 		<welcome-file>index.jsp</welcome-file>
 	</welcome-file-list>

Added: trunk/step/step-web/src/main/webapp/css/setup-layout.css
===================================================================
--- trunk/step/step-web/src/main/webapp/css/setup-layout.css	                        (rev 0)
+++ trunk/step/step-web/src/main/webapp/css/setup-layout.css	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,22 @@
+#installationOptions {
+	min-height: 300px;
+	height: 100%;
+}
+
+#leftColumn {
+	width: 49%;
+	float: left;
+}
+
+#rightColumn { 
+	width: 49%;
+	float: left;
+}
+
+.installed {
+	color: green;
+}
+
+.notInstalled {
+	color: red;
+}

Modified: trunk/step/step-web/src/main/webapp/index.jsp
===================================================================
--- trunk/step/step-web/src/main/webapp/index.jsp	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/index.jsp	2010-12-19 11:27:36 UTC (rev 195)
@@ -18,7 +18,7 @@
     <script src="js/util.js" type="text/javascript"></script>
     <script src="js/passage_toolbar.js" type="text/javascript"></script>
     <script src="js/passage.js" type="text/javascript"></script>
-<!--    <script src="js/bookmark.js" type="text/javascript"></script>-->
+    <script src="js/bookmark.js" type="text/javascript"></script>
     <script src="js/lexicon_definition.js" type="text/javascript"></script>
     <script src="js/ui_hooks.js" type="text/javascript"></script>
     <script src="js/init.js" type="text/javascript"></script>
@@ -44,7 +44,7 @@
 	<div class="ui-layout-north northBookmark">
 		<img src="images/step-logo.png" alt="STEP :: Scripture Tools for Every Pastor" />
 	</div>
-	<div class="ui-layout-center bookmarksContent">b</div>
+	<div id="bookmarkPane" class="ui-layout-center bookmarksContent"><span>Bookmarks</span></div>
 	<div class="ui-layout-south logo">
 		<span class="copyright">&copy; Tyndale House</span>
 	</div>

Modified: trunk/step/step-web/src/main/webapp/js/bookmark.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/bookmark.js	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/js/bookmark.js	2010-12-19 11:27:36 UTC (rev 195)
@@ -5,18 +5,28 @@
  */
 function Bookmark(bookmarkContainer) {
 	this.bookmarkContainer = bookmarkContainer;
+	var self = this;
 	
-	//for bookmarks, we will only have a few, therefore we store them in an array for now:
-	//we will store the elements in here, with their jquery wrapper
-	this.currentBookmarks = [];
+	//listen to passage changes
+	this.bookmarkContainer.hear("passage-change", function(selfElement, data) {
+		self.addHistory(data);
+	});
 }
 
-//
-///**
-// * Adding a bookmark
-// */
-//Bookmark.prototype.add = function(passageReference) {
-//	var bookmark = this.get(passageReference);
+
+/**
+ * Adding a bookmark
+ */
+Bookmark.prototype.addHistory = function(passageReference) {
+	//construct bookmark
+//	var item = "<span>" + passageReference + "</span>";
+//	$("#bookmarkPane span").prepend(item);
+}	
+	
+	
+	
+	
+	//	var bookmark = this.get(passageReference);
 //	if(bookmark) {
 //		//move bookmark around
 //		

Modified: trunk/step/step-web/src/main/webapp/js/init.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/init.js	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/js/init.js	2010-12-19 11:27:36 UTC (rev 195)
@@ -12,6 +12,7 @@
 		initGlobalHandlers();
 		initDefaultValues();
 		initLexicon();
+		initBookmarks();
 		initData();
 	});
 }
@@ -100,7 +101,7 @@
 function initData() {
 	//get all supported versions
 	var options;
-	$.getJSON("rest/bible/features-all", function(data) {
+	$.getJSON(BIBLE_GET_ALL_FEATURES, function(data) {
 		$.each(data, function() {
 			options = data;
 		});
@@ -113,7 +114,7 @@
 	//we reserve the first spot for "ALL Versions"
 	var ii = 1;
 	
-	$.getJSON("rest/bible/versions", function(data) {
+	$.getJSON(BIBLE_GET_BIBLE_VERSIONS, function(data) {
 		var parsedResponse = $.map(data, function(item) {
 			var showingText = "[" + item.initials + "] " + item.name;
 			
@@ -222,9 +223,14 @@
 }
 
 function initLexicon() {
-	var lexicon = new LexiconDefinition();
+	new LexiconDefinition();
 }
 
+function initBookmarks() {
+	new Bookmark($("#bookmarkPane"));
+}
+
+
 function raiseError(error) {
 	$("#error").text(error);
 	$('body').layout().open("north");

Modified: trunk/step/step-web/src/main/webapp/js/lexicon_definition.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/lexicon_definition.js	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/js/lexicon_definition.js	2010-12-19 11:27:36 UTC (rev 195)
@@ -41,7 +41,7 @@
 	
 	var tabs = s.split(" ");
 	$(tabs).each(function() {
-		popup.tabs("add", "rest/module/definitions/" + this, self.getShortKey(this));
+		popup.tabs("add", MODULE_GET_DEFINITION + this, self.getShortKey(this));
 	});
 
 	popup.tabs("option", {

Modified: trunk/step/step-web/src/main/webapp/js/passage.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/passage.js	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/js/passage.js	2010-12-19 11:27:36 UTC (rev 195)
@@ -31,7 +31,6 @@
 		text: false
 	}).change(function() {
 		this.checked ? self.columnLayout.open("north") : self.columnLayout.close("north");
-//		this.checked ? self.toolbar.open() : self.toolbar.close();
 	});
 	
 	
@@ -98,7 +97,7 @@
 	
 	var self = this;
 	if(this.version.val() && this.reference.val() && this.version.val() != "" && this.reference.val() != "") {
-		var url = "rest/bible/text/" + this.version.val() + "/" + this.reference.val();
+		var url = BIBLE_GET_BIBLE_TEXT + this.version.val() + "/" + this.reference.val();
 		
 		if(options && options.length != 0) {
 			url += "/" + options ;
@@ -112,6 +111,9 @@
 		$.get(url, function (text) {
 			//we get html back, so we insert into passage:
 			self.passage.html(text.value);
+			
+			//passage change was successful, so we let the rest of the UI know
+			$.shout("passage-change", self.reference.val());
 		});
 	}
 }

Modified: trunk/step/step-web/src/main/webapp/js/passage_toolbar.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/passage_toolbar.js	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/js/passage_toolbar.js	2010-12-19 11:27:36 UTC (rev 195)
@@ -119,7 +119,7 @@
 	var self = this;
 	
 	//query the server for features
-	$.getJSON("rest/bible/features/" + version, function (features) {
+	$.getJSON(BIBLE_GET_FEATURES + version, function (features) {
 		//for each button, if in array, then enable, otherwise disable
 
 		//TODO: for some reason there are sometime some initialisation issues which throw an exception

Added: trunk/step/step-web/src/main/webapp/js/setup.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/setup.js	                        (rev 0)
+++ trunk/step/step-web/src/main/webapp/js/setup.js	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,39 @@
+$(document).ready(function() {
+	setup();
+});
+
+/**
+ * This method sets up the main page allowing the user to install modules as he/she wishes
+ */
+function setup() {
+	$("#installCoreModules").click(function() {
+		// we add a click handler that installs the default modules
+		$.getJSON(SETUP_INSTALL_DEFAULT_MODULES, function(data) {
+			// installation has started - so now we can afford to make calls to the internet:
+			// set up available modules - to do extend to everything...
+			$.getJSON(MODULE_GET_ALL_INSTALLABLE_MODULES, function(data) {
+				$(data).each(function() {
+					var toBeInstalled = "<a class='notInstalled' href=\"javascript:installVersion('" + this.initials +  "','" + 
+						this.name.replace(/'/g,"\\'")  + "')\">[" + this.initials + "] " + this.name + " - Installed</a><br />";
+					$("#availableModules").append(toBeInstalled);
+				})
+			});
+		});
+	});
+	
+	// set up available modules - to do extend to everything...
+	$.getJSON(MODULE_GET_ALL_MODULES, function(data) {
+		$(data).each(function() {
+			var installed = "<div class=\"installed\">[" + this.initials + "] " + this.name + " - Installed</div>";
+			$("#inProgressModules").append(installed);
+		})
+	});
+}
+
+function installVersion(initials, name) {
+	$.getJSON(SETUP_INSTALL_BIBLE + initials, function(data) {
+		//set up a progress bar on the other side...
+	});
+}
+
+

Modified: trunk/step/step-web/src/main/webapp/js/ui_hooks.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/ui_hooks.js	2010-12-03 19:26:36 UTC (rev 194)
+++ trunk/step/step-web/src/main/webapp/js/ui_hooks.js	2010-12-19 11:27:36 UTC (rev 195)
@@ -3,6 +3,29 @@
  * The aim is to redirect the calls quickly to other parts of the UI
  */
 
+/////////////////////////////////////////////////////////////////////////
+// The following section defines method names and controller names
+// These are used as part of the rest-like calls
+/////////////////////////////////////////////////////////////////////////
+BIBLE_GET_BIBLE_VERSIONS = "rest/bible/getBibleVersions/";
+BIBLE_GET_BIBLE_TEXT = "rest/bible/getBibleText/";
+BIBLE_GET_FEATURES = "rest/bible/getFeatures/";
+BIBLE_GET_ALL_FEATURES = "rest/bible/getAllFeatures/";
+
+MODULE_GET_ALL_MODULES = "rest/module/getAllModules/";
+MODULE_GET_ALL_INSTALLABLE_MODULES = "rest/module/getAllModules/";
+MODULE_GET_DEFINITION = "rest/module/getDefinition/";
+
+SETUP_IS_FIRST_TIME = "rest/setup/isFirstTime/";
+SETUP_INSTALL_DEFAULT_MODULES = "rest/setup/installDefaultModules/";
+SETUP_INSTALL_BIBLE = "rest/setup/installBible/";
+
+TIMELINE_GET_EVENTS = "rest/timeline/getEvents/";
+TIMELINE_GET_EVENTS_FROM_REFERENCE = "rest/timeline/getEventsFromReference/";
+
+
+
+
 /**
  * called when click on a piece of text.
  * @param strongMorphs all the strongs and morphs associated with this "word"

Added: trunk/step/step-web/src/main/webapp/setup.jsp
===================================================================
--- trunk/step/step-web/src/main/webapp/setup.jsp	                        (rev 0)
+++ trunk/step/step-web/src/main/webapp/setup.jsp	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<HTML>
+<HEAD>
+
+    <META http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <TITLE>STEP :: Scripture Tools for Every Pastor</TITLE>
+
+    <link rel="stylesheet" type="text/css" href="css/ui-layout/layout-default.css" />
+    <link rel="stylesheet" type="text/css" href="css/ui-lightness/jquery-ui-1.8.5.custom.css" />
+    <link rel="stylesheet" type="text/css" href="css/initial-layout.css" />
+    <link rel="stylesheet" type="text/css" href="css/initial-fonts.css" />
+    <link rel="stylesheet" type="text/css" href="css/setup-layout.css" />
+    
+    <script src="libs/jquery-1.4.2.min.js" type="text/javascript"></script>
+    <script src="libs/jquery-ui-1.8.5.custom.min.js" type="text/javascript"></script>
+    <script src="libs/jquery.layout-latest.js" type="text/javascript"></script>
+    <script src="libs/jquery-shout.js" type="text/javascript"></script>
+    
+    <script src="js/setup.js" type="text/javascript"></script>
+</HEAD>
+<body>
+
+	<h1>STEP - Scripture Tools for Every Pastor</h1>
+	
+	This is setup page for the STEP software. 
+	This page enables you to install different modules used by STEP, including Bibles, Dictionaries, ...
+	<p />
+	
+	<!-- If the user lives in a country that persecutes Christians then actions on this page might give the game away -->
+	<b>Please note that actions on this page access the internet. If you are in a "sensitive" country, you may wish to wait before you install any modules.</b>
+	<p />
+	
+	A number of modules must be installed for core functionality to be available. 
+	<input id="installCoreModules" type="button" value="Install core functionality" />
+	
+	<div id="installationOptions">
+		<div id="leftColumn" class="column ui-layout-center">
+			<h2>Available modules</h2>
+			
+			<input id="filter" type="text" value="Filter" />
+			
+			<!--  list of links of all available modules, including 
+			dictionaries, broken down by categories -->
+			<div id="availableModules"></div>
+		</div>
+	
+		<div id="rightColumn" class="column ui-layout-east">
+			<h2>Installed modules</h2>
+			<div id="inProgressModules"></div>
+		</div>
+	</div>
+</body>
+</HTML>

Added: trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java
===================================================================
--- trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java	                        (rev 0)
+++ trunk/step/step-web/src/test/java/com/tyndalehouse/step/rest/controllers/FrontControllerTest.java	2010-12-19 11:27:36 UTC (rev 195)
@@ -0,0 +1,126 @@
+package com.tyndalehouse.step.rest.controllers;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+import org.junit.Test;
+
+import com.google.inject.Injector;
+import com.tyndalehouse.step.core.service.BibleInformationService;
+
+/**
+ * tests the front controller parsing process
+ * 
+ * @author Chris
+ * 
+ */
+public class FrontControllerTest {
+
+    /**
+     * tests that arguments are parsed correctly given the correct start
+     */
+    @Test
+    public void testGetArgs() {
+        // index starts at ...........0123456789-123456789-123456
+        final String sampleRequest = "step-web/rest/bible/get/1K2/2K2";
+
+        final FrontController fc = new FrontController(mock(Injector.class));
+
+        // when
+        final Object[] args = fc.getArgs(sampleRequest, 24);
+
+        // then
+        assertEquals(2, args.length);
+        assertEquals("1K2", args[0]);
+        assertEquals("2K2", args[1]);
+    }
+
+    /**
+     * tests that parsing of request works if request finishes with a slash
+     */
+    @Test
+    public void testGetArgsFinishingWithSlash() {
+        // index starts at ...........0123456789-123456789-123456
+        final String sampleRequest = "step-web/rest/bible/get/1K2/2K2/";
+
+        final FrontController fc = new FrontController(mock(Injector.class));
+
+        // when
+        final Object[] args = fc.getArgs(sampleRequest, 24);
+
+        // then
+        assertEquals(2, args.length);
+        assertEquals("1K2", args[0]);
+        assertEquals("2K2", args[1]);
+    }
+
+    /**
+     * tests generation of cache key
+     */
+    @Test
+    public void testCacheKey() {
+        assertEquals("controllergetName",
+                new FrontController(mock(Injector.class)).getCacheKey("controller", "getName", null));
+    }
+
+    /**
+     * tests that resolving method works
+     * 
+     * @throws IllegalAccessException uncaught exception
+     * @throws InvocationTargetException uncaught exception
+     */
+    @Test
+    public void testGetControllerMethod() throws IllegalAccessException, InvocationTargetException {
+        final FrontController frontController = new FrontController(mock(Injector.class));
+        final BibleInformationService bibleInfo = mock(BibleInformationService.class);
+        final BibleController controllerInstance = new BibleController(bibleInfo);
+
+        // when
+        final Method controllerMethod = frontController.getControllerMethod("getBibleVersions",
+                controllerInstance, null);
+
+        // then
+        controllerMethod.invoke(controllerInstance);
+        verify(bibleInfo).getAvailableBibleVersions();
+    }
+
+    /**
+     * tests the get controller method
+     */
+    @Test
+    public void testGetController() {
+        final String controllerName = "Bible";
+        final Injector mockInjector = mock(Injector.class);
+        final FrontController frontController = new FrontController(mockInjector);
+
+        final BibleController mockController = mock(BibleController.class);
+        when(mockInjector.getInstance(BibleController.class)).thenReturn(mockController);
+
+        // when
+        final Object controller = frontController.getController(controllerName);
+
+        // then
+        assertEquals(controller.getClass(), mockController.getClass());
+    }
+
+    /**
+     * tests various combinations for getClasses
+     */
+    @Test
+    public void testGetClasses() {
+        final FrontController fc = new FrontController(null);
+
+        assertEquals(0, fc.getClasses(null).length);
+        assertEquals(0, fc.getClasses(new Object[0]).length);
+        assertArrayEquals(new Class<?>[] { String.class, ArrayList.class },
+                fc.getClasses(new Object[] { "hello", new ArrayList<String>() }));
+
+    }
+}




More information about the Tynstep-svn mailing list