changeset 1623:5418b39dd49f

Merge from iiif-presentation branch 62246fdad98050c4c371e0e6c2d8e5c56a73c092
author Robert Casties <casties@mpiwg-berlin.mpg.de>
date Thu, 01 Jun 2017 15:06:02 +0200
parents 3f3a4f4eecb1 (current diff) 62246fdad980 (diff)
children 373b05148ab2
files servlet3/pom.xml.orig text/pom.xml.orig webapp/pom.xml.orig webapp/src/main/webapp/jquery/digilib-auth.html.orig webapp/src/main/webapp/jquery/digilib.html.orig webapp/src/main/webapp/jquery/jquery.digilib-ann.css webapp/src/main/webapp/jquery/jquery.digilib-ann.js webapp/src/main/webapp/jquery/jquery.digilib-ann.min.css webapp/src/main/webapp/jquery/jquery.digilib-ann.min.js webapp/src/main/webapp/jquery/jquery.digilib-ann.min.js.map webapp/src/main/webapp/jquery/jquery.digilib-auth.css webapp/src/main/webapp/jquery/jquery.digilib-auth.js webapp/src/main/webapp/jquery/jquery.digilib-auth.min.css webapp/src/main/webapp/jquery/jquery.digilib-auth.min.js
diffstat 33 files changed, 1475 insertions(+), 188 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Mar 08 13:12:01 2017 +0100
+++ b/.hgignore	Thu Jun 01 15:06:02 2017 +0200
@@ -129,4 +129,12 @@
 syntax: regexp
 ^webapp/src/main/webapp/jquery/jquery\.digilib-basic\.js$
 syntax: regexp
-^webapp/src/main/webapp/jquery/jquery\.digilib-basic\.min\.css$
\ No newline at end of file
+^webapp/src/main/webapp/jquery/jquery\.digilib-basic\.min\.css$
+syntax: regexp
+^iiif-presentation/target$
+syntax: regexp
+^iiif-presentation/\.settings$
+syntax: regexp
+^iiif-presentation/\.classpath$
+syntax: regexp
+^iiif-presentation/\.project$
\ No newline at end of file
--- a/common/src/main/java/digilib/conf/DigilibConfiguration.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/common/src/main/java/digilib/conf/DigilibConfiguration.java	Thu Jun 01 15:06:02 2017 +0200
@@ -57,7 +57,7 @@
 
     /** digilib version */
     public static String getClassVersion() {
-        return "2.5.2a";
+        return "2.5.3a";
     }
 
     /* non-static getVersion for Java inheritance */
@@ -98,8 +98,6 @@
         newParameter("iiif-prefix", "IIIF", null, 'f');
         // IIIF Image API version to support (mostly relevant for info.json)
         newParameter("iiif-api-version", "2.0", null, 'f');        
-        // set CORS header on IIIF Image API info request
-        newParameter("iiif-info-cors", Boolean.TRUE, null, 'f');        
         // character to use as slash-replacement in IIIF identifier part
         newParameter("iiif-slash-replacement", "!", null, 'f');        
     }
--- a/common/src/main/java/digilib/conf/DigilibRequest.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/common/src/main/java/digilib/conf/DigilibRequest.java	Thu Jun 01 15:06:02 2017 +0200
@@ -31,6 +31,9 @@
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
 import java.util.StringTokenizer;
 
 import org.apache.log4j.Logger;
@@ -63,13 +66,26 @@
 public class DigilibRequest extends ParameterMap {
 
     private static Logger logger = Logger.getLogger("digilib.request");
+    
+    /**
+     * special options for parsing the request. 
+     */
+    public static enum ParsingOption {
+    	omitIiifImageApi
+    }
 
+    /** active pasing options */
+    public EnumSet<ParsingOption> parsingOptions = EnumSet.noneOf(ParsingOption.class);
+    
     /** IIIF path prefix (taken from config) */
     protected String iiifPrefix = "IIIF";
     
     /** IIIF slash replacement (taken from config) */
     protected String iiifSlashReplacement = null;
     
+    /** parse IIIF path as IIIF image API */
+    public boolean parseIiifImageApi = true;
+    
     /** error message while configuring */
     public String errorMessage = null;
 
@@ -154,6 +170,9 @@
         newParameter("request.path", "", null, 'i');
         // base URL (from http:// to below /servlet)
         newParameter("base.url", null, null, 'i');
+        // elements of IIIF API path
+        newParameter("request.iiif.elements", null, null, 'i');
+        
         /*
          * Parameters of type 'c' are for the clients use
          */
@@ -291,13 +310,9 @@
             return false;
         }
         
-        String identifier = null;
-        String region = null;
-        String size = null;
-        String rotation = null;
-        String quality = null;
-        String format = null;
-
+        List<String> params = new ArrayList<String>(5);
+        setValue("request.iiif.elements", params);
+        
         // enable passing of delimiter to get empty parameters
         StringTokenizer query = new StringTokenizer(path, "/", true);
         String token;
@@ -317,80 +332,89 @@
             }
         }
         /*
-         * second parameter identifier (encoded)
+         * following parameters
          */
-        if (query.hasMoreTokens()) {
+        while (query.hasMoreTokens()) {
             token = getNextDecodedToken(query);
             if (!token.equals("/")) {
-                identifier = token;
-                // skip /
-                if (query.hasMoreTokens()) {
-                    query.nextToken();
-                }
-            }
-        }
-        /*
-         * third parameter region
-         */
-        if (query.hasMoreTokens()) {
-            token = getNextDecodedToken(query);
-            if (!token.equals("/")) {
-                region = token;
-                // skip /
-                if (query.hasMoreTokens()) {
-                    query.nextToken();
-                }
-            }
-        }
-        /*
-         * fourth parameter size
-         */
-        if (query.hasMoreTokens()) {
-            token = getNextDecodedToken(query);
-            if (!token.equals("/")) {
-                size = token;
+            	params.add(token);
                 // skip /
                 if (query.hasMoreTokens()) {
                     query.nextToken();
                 }
-            }
-        }
-        /*
-         * fifth parameter rotation
-         */
-        if (query.hasMoreTokens()) {
-            token = getNextDecodedToken(query);
-            if (!token.equals("/")) {
-                rotation = token;
-                // skip /
-                if (query.hasMoreTokens()) {
-                    query.nextToken();
-                }
-            }
-        }
-        /*
-         * sixth parameter quality.format
-         */
-        if (query.hasMoreTokens()) {
-            token = getNextDecodedToken(query);
-            // quality.format -- color depth and output format
-            try {
-                String[] parms = token.split("\\.");
-                // quality param
-                quality = parms[0];
-                // format param
-                if (parms.length > 1) {
-                    format = parms[1];
-                }
-            } catch (Exception e) {
-                errorMessage = "Error parsing quality and format parameters in IIIF path!";
-                logger.error(errorMessage, e);
-                return false;
+            } else {
+            	// empty parameter
+            	params.add(null);
             }
         }
 
+        if (parsingOptions.contains(ParsingOption.omitIiifImageApi)) {
+        	return true;
+        }
+        
+        /*
+         * parse sequence of parameters as IIIF image API
+         */
+        String identifier = null;
+        String region = null;
+        String size = null;
+        String rotation = null;
+        String quality = null;
+        String format = null;
+
+		if (params.size() > 0) {
+			/*
+			 * first parameter identifier (encoded)
+			 */
+			identifier = params.get(0);
+			
+			if (params.size() > 1) {
+				/*
+				 * second parameter region
+				 */
+				region = params.get(1);
+				
+				if (params.size() > 2) {
+					/*
+					 * third parameter size
+					 */
+					size = params.get(2);
+					
+					if (params.size() > 3) {
+						/*
+						 * fourth parameter rotation
+						 */
+						rotation = params.get(3);
+						
+						if (params.size() > 4) {
+							/*
+							 * fifth parameter quality.format
+							 */
+							String qf = params.get(4);
+							if (qf != null) {
+								// quality.format -- color depth and output
+								// format
+								try {
+									String[] parms = qf.split("\\.");
+									// quality param
+									quality = parms[0];
+									// format param
+									if (parms.length > 1) {
+										format = parms[1];
+									}
+								} catch (Exception e) {
+									errorMessage = "Error parsing quality and format parameters in IIIF path!";
+									logger.error(errorMessage, e);
+									return false;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
         // set request with these parameters
-        return setWithIiifParams(identifier, region, size, rotation, quality, format);        
+        return setWithIiifImageParams(identifier, region, size, rotation, quality, format);
     }
 
     private String getNextDecodedToken(StringTokenizer tokens) {
@@ -417,7 +441,7 @@
 	 * @param format
 	 * @return
 	 */
-	public boolean setWithIiifParams(String identifier, String region, String size, 
+	public boolean setWithIiifImageParams(String identifier, String region, String size, 
 			String rotation, String quality, String format) {
         // alway set HTTP status code error reporting
         options.setOption(DigilibOption.errcode);
@@ -427,14 +451,7 @@
          */
         if (identifier != null) {
             try {
-                if (identifier.contains("%")) {
-                    // still escape chars -- decode again
-                    identifier = URLDecoder.decode(identifier, "UTF-8");
-                }
-                if (iiifSlashReplacement != null && identifier.contains(iiifSlashReplacement)) {
-                    // change replacement back to slash
-                    identifier = identifier.replace(iiifSlashReplacement, "/");
-                }
+                identifier = decodeIiifIdentifier(identifier);
                 setValueFromString("fn", identifier);
             } catch (UnsupportedEncodingException e) {
                 errorMessage = "Error decoding identifier in IIIF path!";
@@ -614,6 +631,23 @@
         return true;
 	}
 
+	/**
+	 * @param identifier
+	 * @return
+	 * @throws UnsupportedEncodingException
+	 */
+	public String decodeIiifIdentifier(String identifier) throws UnsupportedEncodingException {
+		if (identifier.contains("%")) {
+		    // still escape chars -- decode again
+		    identifier = URLDecoder.decode(identifier, "UTF-8");
+		}
+		if (iiifSlashReplacement != null && identifier.contains(iiifSlashReplacement)) {
+		    // change replacement back to slash
+		    identifier = identifier.replace(iiifSlashReplacement, "/");
+		}
+		return identifier;
+	}
+
 	
     /**
      * Test if option string <code>opt</code> is set. Checks if the substring
--- a/common/src/main/java/digilib/io/DocuDirectory.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/common/src/main/java/digilib/io/DocuDirectory.java	Thu Jun 01 15:06:02 2017 +0200
@@ -30,6 +30,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
 import digilib.conf.DigilibConfiguration;
@@ -47,7 +48,7 @@
  * 
  * @author casties
  */
-public abstract class DocuDirectory extends Directory {
+public abstract class DocuDirectory extends Directory implements Iterable<DocuDirent> {
 
     /** type of files in this DocuDirectory */
     protected FileClass fileClass = FileClass.IMAGE;
@@ -347,6 +348,15 @@
     public DirMeta getMeta() {
         return meta;
     }
+    
+    /**
+     * Returns an Iterator over all DocuDirents in this DocuDirectory in default order.
+     * 
+     * @return
+     */
+    public Iterator<DocuDirent> iterator() {
+    	return files.iterator();
+    }
 
     private boolean isBasenameInList(List<DocuDirent> fileList, int idx, String fn) {
     	String dfn = FileOps.basename((fileList.get(idx)).getName());
--- a/common/src/main/java/digilib/util/ParameterMap.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/common/src/main/java/digilib/util/ParameterMap.java	Thu Jun 01 15:06:02 2017 +0200
@@ -130,7 +130,7 @@
 	
 	/** Get the Parameter with the corresponding key.
 	 * 
-	 * Returns null if no element is associated with key.
+	 * Returns empty string if no element is associated with key.
 	 * 
 	 * @param key
 	 * @return
@@ -142,7 +142,7 @@
 
 	/** Get the Parameter with the corresponding key.
 	 * 
-	 * Returns null if no element is associated with key.
+	 * Returns 0 if no element is associated with key.
 	 * 
 	 * @param key
 	 * @return
@@ -154,7 +154,7 @@
 
 	/** Get the Parameter with the corresponding key.
 	 * 
-	 * Returns null if no element is associated with key.
+	 * Returns 0 if no element is associated with key.
 	 * 
 	 * @param key
 	 * @return
@@ -166,7 +166,7 @@
 
 	/** Get the Parameter with the corresponding key.
 	 * 
-	 * Returns null if no element is associated with key.
+	 * Returns false if no element is associated with key.
 	 * 
 	 * @param key
 	 * @return
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iiif-presentation/pom.xml	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<project
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>digilib</groupId>
+		<artifactId>digilib</artifactId>
+		<version>2.5-SNAPSHOT</version>
+	</parent>
+	<artifactId>digilib-iiif-presentation</artifactId>
+	<name>digilib-iiif-presentation</name>
+	<description>The Digital Image Library - IIIF presentation API manifest serving servlet</description>
+	<url>http://digilib.sourceforge.net</url>
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+	<dependencies>
+		<dependency>
+			<groupId>digilib</groupId>
+			<artifactId>digilib-servlet</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.mortbay.jetty</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>3.0.20100224</version>
+			<type>jar</type>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.json</groupId>
+			<artifactId>javax.json-api</artifactId>
+			<version>1.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.glassfish</groupId>
+			<artifactId>javax.json</artifactId>
+			<version>1.1</version>
+		</dependency>
+	</dependencies>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iiif-presentation/src/main/java/digilib/conf/ManifestServletConfiguration.java	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,114 @@
+package digilib.conf;
+
+/*
+ * #%L
+ * 
+ * ManifesteServletConfiguration.java
+ * 
+ * Digital Image Library servlet components
+ * %%
+ * Copyright (C) 2003 - 2017 MPIWG Berlin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as 
+ * published by the Free Software Foundation, either version 3 of the 
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Lesser Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Lesser Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ * Author: Robert Casties (robcast@sourceforge.net)
+ * Created on 24.5.2017
+ */
+
+import javax.servlet.ServletContext;
+import javax.servlet.annotation.WebListener;
+
+/**
+ * Class to hold the digilib servlet configuration parameters. The parameters
+ * can be read from the digilib-config file and be passed to other servlets or
+ * beans.
+ * 
+ * @author casties
+ */
+@WebListener
+public class ManifestServletConfiguration extends DigilibServletConfiguration {
+
+    public static final String MANIFEST_SERVLET_CONFIG_KEY = "digilib.manifest.servlet.configuration";
+    
+    public static String getClassVersion() {
+        return DigilibConfiguration.getClassVersion() + " manif";
+    }
+
+    /** non-static getVersion for Java inheritance */
+    @Override
+    public String getVersion() {
+    	return getClassVersion();
+    }
+    
+    /**
+     * Constructs DigilibServletConfiguration and defines all parameters and
+     * their default values.
+     */
+    public ManifestServletConfiguration() {
+        super();
+
+        // Scaler servlet name used in constructing IIIF image API paths
+        newParameter("scaler-servlet-path", "Scaler", null, 'f');
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see digilib.conf.DigilibServletConfiguration#configure(javax.servlet.
+     * ServletContext)
+     */
+    @Override
+    public void configure(ServletContext context) {
+        super.configure(context);
+
+        // set version
+        setValue("servlet.version", getVersion());
+
+    }
+
+    /**
+     * Sets the current DigilibConfiguration in the context. 
+     * @param context
+     */
+    @Override
+    public void setContextConfig(ServletContext context) {
+        context.setAttribute(ManifestServletConfiguration.MANIFEST_SERVLET_CONFIG_KEY, this);
+    }
+    
+    /**
+     * Returns the current TextServletConfiguration from the context.
+     * 
+     * @param context
+     * @return
+     */
+    public static DigilibServletConfiguration getCurrentConfig(ServletContext context) {
+        DigilibServletConfiguration config = (DigilibServletConfiguration) context
+                .getAttribute(ManifestServletConfiguration.MANIFEST_SERVLET_CONFIG_KEY);
+        return config;
+    }
+
+    /**
+     * Returns the current DigilibConfiguration from the context.
+     * (non-static method, for Java inheritance)
+     * 
+     * @param context
+     * @return
+     */
+    @Override
+    protected DigilibServletConfiguration getContextConfig(ServletContext context) {
+        return getCurrentConfig(context);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iiif-presentation/src/main/java/digilib/servlet/Manifester.java	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,523 @@
+package digilib.servlet;
+
+/*
+ * #%L
+ * 
+ * Manifester.java -- Servlet for creating IIIF Presentation API manifests.
+ * 
+ * Digital Image Library servlet components
+ * %%
+ * Copyright (C) 2003 - 2017 MPIWG Berlin
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as 
+ * published by the Free Software Foundation, either version 3 of the 
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Lesser Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Lesser Public 
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * #L%
+ * Author: Robert Casties (robcast@sourceforge.net)
+ * Created on 24.5.2017
+ */
+
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.List;
+
+import javax.json.Json;
+import javax.json.stream.JsonGenerator;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+
+import digilib.auth.AuthOpException;
+import digilib.auth.AuthzOps;
+import digilib.conf.DigilibRequest.ParsingOption;
+import digilib.conf.DigilibServletConfiguration;
+import digilib.conf.DigilibServletRequest;
+import digilib.conf.ManifestServletConfiguration;
+import digilib.io.DocuDirCache;
+import digilib.io.DocuDirectory;
+import digilib.io.DocuDirent;
+import digilib.io.FileOps;
+import digilib.io.ImageFileSet;
+import digilib.io.ImageInput;
+import digilib.util.ImageSize;
+
+/**
+ * Servlet for creating IIIF Presentation API manifests.
+ * 
+ * 
+ * @author casties
+ * 
+ */
+public class Manifester extends HttpServlet {
+
+	private static final long serialVersionUID = 6678666342141409868L;
+
+	/** Servlet version */
+	public static String mfVersion = ManifestServletConfiguration.getClassVersion();
+
+	/** DigilibConfiguration instance */
+	protected DigilibServletConfiguration dlConfig = null;
+
+	/** general logger */
+	protected Logger logger = Logger.getLogger("digilib.manifester");
+
+	/** logger for accounting requests */
+	protected static Logger accountlog = Logger.getLogger("account.manifester.request");
+
+	/** AuthOps instance */
+	protected AuthzOps authzOp;
+
+	/** DocuDirCache instance */
+	protected DocuDirCache dirCache;
+
+	/** use authentication */
+	protected boolean useAuthorization = false;
+	
+	/** scaler servlet path */
+	protected String scalerServletPath;
+
+	/** character for IIIF path separation */
+	protected String iiifPathSep;
+
+    /** set CORS header ACAO* for info requests */
+    protected boolean corsForInfoRequests = true;
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+	 */
+	public void init(ServletConfig config) throws ServletException {
+		super.init(config);
+
+		System.out.println("***** Digital Image Library IIF Manifest Servlet (version " + mfVersion + ") *****");
+
+		// get our ServletContext
+		ServletContext context = config.getServletContext();
+		// see if there is a Configuration instance
+		dlConfig = ManifestServletConfiguration.getCurrentConfig(context);
+		if (dlConfig == null) {
+			// no Configuration
+			throw new ServletException("No Configuration!");
+		}
+		// say hello in the log file
+		logger.info("***** Digital Image Library IIIF Manifest Servlet (version " + mfVersion + ") *****");
+
+		// set our AuthOps
+		useAuthorization = dlConfig.getAsBoolean("use-authorization");
+		authzOp = (AuthzOps) dlConfig.getValue(DigilibServletConfiguration.AUTHZ_OP_KEY);
+		// DocuDirCache instance
+		dirCache = (DocuDirCache) dlConfig.getValue(DigilibServletConfiguration.DIR_CACHE_KEY);
+		// Scaler path
+		scalerServletPath = dlConfig.getAsString("scaler-servlet-path");
+		// IIIF path separator
+		iiifPathSep = dlConfig.getAsString("iiif-slash-replacement");
+		// CORS for info requests
+		corsForInfoRequests = dlConfig.getAsBoolean("iiif-info-cors");
+	}
+
+    /**
+     * Returns modification time relevant to the request for caching.
+     * 
+     * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest)
+     */
+    public long getLastModified(HttpServletRequest request) {
+        accountlog.debug("GetLastModified from " + request.getRemoteAddr() + " for " + request.getQueryString());
+        long mtime = -1;
+        try {
+            // create new digilib request
+			DigilibServletRequest dlRequest = new DigilibServletRequest(request, dlConfig,
+					EnumSet.of(ParsingOption.omitIiifImageApi));
+			// get list of IIIF parameters
+			@SuppressWarnings("unchecked")
+			List<String> iiifParams = (List<String>) dlRequest.getValue("request.iiif.elements");
+			// get identifier (first parameter)
+			String identifier = iiifParams.get(0);
+			// decode identifier to file path
+			dlRequest.setValueFromString("fn", dlRequest.decodeIiifIdentifier(identifier));
+            DocuDirectory dd = dirCache.getDirectory(dlRequest.getFilePath());
+            if (dd != null) {
+                mtime = dd.getDirMTime() / 1000 * 1000;
+            }
+        } catch (Exception e) {
+            logger.error("error in getLastModified: " + e.getMessage());
+        }
+        logger.debug("  returns " + mtime);
+        return mtime;
+    }
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.
+	 * HttpServletRequest, javax.servlet.http.HttpServletResponse)
+	 */
+	protected void doGet(HttpServletRequest request, HttpServletResponse response)
+			throws ServletException, IOException {
+		accountlog.info("GET from " + request.getRemoteAddr());
+		// do the processing
+		processRequest(request, response);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.
+	 * HttpServletRequest, javax.servlet.http.HttpServletResponse)
+	 */
+	protected void doPost(HttpServletRequest request, HttpServletResponse response)
+			throws ServletException, IOException {
+		accountlog.info("POST from " + request.getRemoteAddr());
+		// do the processing
+		processRequest(request, response);
+	}
+
+	protected void processRequest(HttpServletRequest request, HttpServletResponse response) {
+		try {
+			// create DigilibRequest from ServletRequest, omit IIIF Image API parsing
+			DigilibServletRequest dlRequest = new DigilibServletRequest(request, dlConfig,
+					EnumSet.of(ParsingOption.omitIiifImageApi));
+			// get list of IIIF parameters
+			@SuppressWarnings("unchecked")
+			List<String> iiifParams = (List<String>) dlRequest.getValue("request.iiif.elements");
+			if (iiifParams == null) {
+				logger.error("Invalid IIIF request.");
+				response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid IIIF request.");
+				return;
+			}
+			// get identifier (first parameter)
+			String identifier = iiifParams.get(0);
+			if (identifier == null) {
+				logger.error("IIIF identifier missing");
+				response.sendError(HttpServletResponse.SC_BAD_REQUEST, "IIIF identifier missing.");
+				return;
+			}
+			// decode identifier to file path
+			dlRequest.setValueFromString("fn", dlRequest.decodeIiifIdentifier(identifier));
+			// get directory path
+			String dlFn = dlRequest.getFilePath();
+			// get information about the directory
+			DocuDirectory dlDir = dirCache.getDirectory(dlFn);
+			if (dlDir == null) {
+				logger.error("Directory for manifest not found: " + dlFn);
+				response.sendError(HttpServletResponse.SC_NOT_FOUND);
+				return;
+			}
+            if (dlDir.size() == 0) {
+                logger.debug("Directory has no files: " + dlFn);
+                response.sendError(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+
+            ManifestParams params = new ManifestParams();
+
+            /*
+			 * set CORS header ACAO "*" for info response as per IIIF spec
+			 */
+			if (corsForInfoRequests) {
+				String origin = request.getHeader("Origin");
+				if (origin != null) {
+					response.setHeader("Access-Control-Allow-Origin", "*");
+				}
+			}
+
+            /*
+             * check permissions
+             */
+            if (useAuthorization) {
+                // is the current request/user authorized?
+                if (!authzOp.isAuthorized(dlRequest)) {
+                	// TODO: does this work for directories?
+                    // send deny answer and abort
+                    throw new AuthOpException("Access denied!");
+                }
+            }
+
+			// use JSON-LD content type only when asked
+			String accept = request.getHeader("Accept");
+			if (accept != null && accept.contains("application/ld+json")) {
+				response.setContentType("application/ld+json");
+			} else {
+				response.setContentType("application/json");
+			}
+
+			/*
+			 * get manifest base URL
+			 */
+			String url = request.getRequestURL().toString();
+			// get base URL for Servlets
+			int srvPathLen = request.getServletPath().length() + request.getPathInfo().length();
+			String servletBaseUrl = url.substring(0, url.length() - srvPathLen);
+			// manifest base URL
+			String baseurl = servletBaseUrl + request.getServletPath() + "/" + dlConfig.getAsString("iiif-prefix") + "/" + identifier;
+			
+			params.manifestUrl = baseurl;
+			params.imgApiUrl = servletBaseUrl +"/" + this.scalerServletPath + "/" + dlConfig.getAsString("iiif-prefix");
+			params.identifier = identifier;
+			params.docuDir = dlDir;
+			
+			/*
+			 * start json representation
+			 */
+			ServletOutputStream out = response.getOutputStream();
+			JsonGenerator manifest = Json.createGenerator(out).writeStartObject();
+			/*
+			 * manifest metadata
+			 */
+			writeManifestMeta(manifest, dlFn, params);
+			
+			/*
+			 * sequences
+			 */
+			writeSequences(manifest, params);
+			
+			manifest.writeEnd(); // manifest
+			manifest.close();
+
+		} catch (IOException e) {
+			logger.error("ERROR sending manifest: ", e);
+		} catch (AuthOpException e) {
+			logger.debug("Permission denied.");
+			try {
+				response.sendError(HttpServletResponse.SC_FORBIDDEN);
+			} catch (IOException e1) {
+				logger.error("Error sending error: ", e);
+			}
+		}
+	}
+
+    /**
+     * @param manifest
+     * @param dlFn
+     * @param params 
+     */
+    protected void writeManifestMeta(JsonGenerator manifest, String dlFn, ManifestParams params) {
+        manifest.write("@context", "http://iiif.io/api/presentation/2/context.json")
+            .write("@type", "sc:Manifest")
+            .write("@id", params.manifestUrl + "/manifest")
+            .write("label", "[Scanned work " + dlFn + "]")
+            .write("description", "[Automatically generated manifest for scanned work " + dlFn + "]");
+    }
+
+    /**
+     * @param dlDir
+     * @param url
+     * @param manifest
+     * @param servletBaseUrl 
+     */
+    protected void writeSequences(JsonGenerator manifest, ManifestParams params) {
+        manifest.writeStartArray("sequences");
+        /*
+         * first sequence
+         */
+        writeSequence(manifest, params);
+        
+        manifest.writeEnd(); // sequences
+    }
+
+	/**
+	 * @param dlDir
+	 * @param url
+	 * @param manifest
+	 * @param servletUrl 
+	 */
+	protected void writeSequence(JsonGenerator manifest, ManifestParams params) {
+		manifest.writeStartObject()
+			.write("@id", params.manifestUrl + "/sequence/default")
+			.write("@type", "sc:Sequence")
+			.write("label", "Scan image order");
+		/*
+		 * canvases
+		 */
+		writeCanvases(manifest, params);
+		
+		manifest.writeEnd(); // sequence
+	}
+
+	/**
+	 * @param dlDir
+	 * @param url
+	 * @param manifest
+	 * @param servletUrl 
+	 */
+	protected void writeCanvases(JsonGenerator manifest, ManifestParams params) {
+		/*
+		 * list of canvases
+		 */
+		manifest.writeStartArray("canvases");
+		
+		int idx = 0;
+		for (DocuDirent imgFile : params.docuDir) {
+			idx += 1;
+			ImageFileSet imgFs = (ImageFileSet) imgFile;
+			ImageInput img = imgFs.getBiggest();
+			ImageSize imgSize = img.getSize();
+			/*
+			 * canvas
+			 */
+			writeCanvas(manifest, idx, imgFile, imgSize, params);
+		}
+		
+		manifest.writeEnd(); // canvases
+	}
+
+	/**
+	 * @param url
+	 * @param manifest
+	 * @param idx
+	 * @param imgFile
+	 * @param imgSize
+	 * @param servletUrl 
+	 */
+    protected void writeCanvas(JsonGenerator manifest, int idx, DocuDirent imgFile, ImageSize imgSize,
+            ManifestParams params) {
+        manifest.writeStartObject()
+            .write("@type", "sc:Canvas")
+            .write("@id", params.manifestUrl + "/canvas/p" + idx)
+            .write("label", "image " + FileOps.basename(imgFile.getName()))
+            .write("height", imgSize.getHeight())
+            .write("width", imgSize.getWidth());
+        /*
+         * images
+         */
+        writeImages(manifest, idx, imgFile, imgSize, params);
+
+        manifest.writeEnd(); // canvas
+    }
+
+	/**
+	 * @param url
+	 * @param manifest
+	 * @param idx
+	 * @param imgFile
+	 * @param imgSize
+	 * @param servletUrl 
+	 */
+    protected void writeImages(JsonGenerator manifest, int idx, DocuDirent imgFile, ImageSize imgSize,
+            ManifestParams params) {
+        /*
+         * list of images (just one)
+         */
+        manifest.writeStartArray("images");
+        /*
+         * image
+         */
+        writeImage(manifest, idx, imgFile, imgSize, params);
+
+        manifest.writeEnd(); // images
+    }
+
+	/**
+	 * @param url
+	 * @param manifest
+	 * @param idx
+	 * @param imgFile
+	 * @param imgSize
+	 * @param servletUrl 
+	 */
+    protected void writeImage(JsonGenerator manifest, int idx, DocuDirent imgFile, ImageSize imgSize,
+            ManifestParams params) {
+        /*
+         * image
+         */        
+        manifest.writeStartObject()
+            .write("@type", "oa:Annotation")
+            .write("@id", params.manifestUrl + "/annotation/p" + idx + "-image")
+            .write("motivation", "sc:painting");
+        /*
+         * resource
+         */
+        writeResource(manifest, imgFile, imgSize, params);
+
+        manifest.write("on", params.manifestUrl + "/canvas/p" + idx)
+            .writeEnd(); // image
+    }
+
+	/**
+	 * @param url
+	 * @param manifest
+	 * @param imgFile
+	 * @param imgSize
+	 * @param servletUrl 
+	 */
+    protected void writeResource(JsonGenerator manifest, DocuDirent imgFile, ImageSize imgSize,
+            ManifestParams params) {
+        // base URL for image using IIIF image API
+        String iiifImgBaseUrl = params.imgApiUrl + "/" + params.identifier + this.iiifPathSep + FileOps.basename(imgFile.getName());
+        // IIIF image parameters
+        String imgUrl = iiifImgBaseUrl + "/full/full/0/default.jpg";
+        /*
+         * resource
+         */
+		manifest.writeStartObject("resource")
+			.write("@id", imgUrl)
+			.write("@type", "dctypes:Image")
+			.write("format", "image/jpeg")
+		    .write("height", imgSize.getHeight())
+			.write("width", imgSize.getWidth());
+        /*
+         * (iiif) service
+         */
+        writeService(manifest, iiifImgBaseUrl, imgSize, params);
+        
+        manifest.writeEnd(); // resource
+	}
+
+	/**
+	 * @param manifest
+	 * @param iiifImgBaseUrl 
+	 * @param imgSize 
+	 * @param servletUrl 
+	 */
+    protected void writeService(JsonGenerator manifest, String iiifImgBaseUrl, ImageSize imgSize,
+            ManifestParams params) {
+	    /*
+	     * service
+	     */
+		manifest.writeStartObject("service")
+			.write("@context", "http://iiif.io/api/image/2/context.json")
+			.write("@id", iiifImgBaseUrl)
+			.write("profile", "http://iiif.io/api/image/2/profiles/level2.json")
+			// maximum size
+            .write("height", imgSize.getHeight())
+            .write("width", imgSize.getWidth())
+            /* other sizes
+            .writeStartArray("sizes")
+            .writeStartObject()
+            .write("width", 100)
+            .write("height", 100)
+            .writeEnd() // size
+            .writeEnd() // sizes
+            */
+            
+			.writeEnd(); // service
+	}
+
+	/**
+	 * Class holding parameters to construct manifest.
+	 * @author casties
+	 *
+	 */
+	protected class ManifestParams {
+	    public DocuDirectory docuDir;
+        String manifestUrl;
+	    String imgApiUrl;
+	    String identifier;	    
+	}
+}
\ No newline at end of file
--- a/pom.xml	Wed Mar 08 13:12:01 2017 +0100
+++ b/pom.xml	Thu Jun 01 15:06:02 2017 +0200
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
 
   <properties>
@@ -158,6 +157,12 @@
       </modules>
     </profile>
     <profile>
+      <id>iiif-presentation</id>
+      <modules>
+        <module>iiif-presentation</module>
+      </modules>
+    </profile>
+    <profile>
       <id>pdf</id>
       <modules>
         <module>pdf</module>
@@ -230,6 +235,11 @@
       </dependency>
       <dependency>
         <groupId>digilib</groupId>
+        <artifactId>digilib-iiif-presentation</artifactId>
+        <version>2.5-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>digilib</groupId>
         <artifactId>digilib-servlet</artifactId>
         <version>2.5-SNAPSHOT</version>
       </dependency>
--- a/servlet/src/main/java/digilib/conf/DigilibServletConfiguration.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/servlet/src/main/java/digilib/conf/DigilibServletConfiguration.java	Thu Jun 01 15:06:02 2017 +0200
@@ -171,6 +171,10 @@
         newParameter("docudirectory-class", "digilib.io.BaseDirDocuDirectory", null, 'f');
         // name of cookie with authentication token
         newParameter("authn-token-cookie", "id_token", null, 'f');
+        // set CORS header on IIIF Image API info request
+        newParameter("iiif-info-cors", Boolean.TRUE, null, 'f');        
+        // set CORS header on IIIF Image API image request
+        newParameter("iiif-image-cors", Boolean.TRUE, null, 'f');        
     }
 
     /**
--- a/servlet/src/main/java/digilib/conf/DigilibServletRequest.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/servlet/src/main/java/digilib/conf/DigilibServletRequest.java	Thu Jun 01 15:06:02 2017 +0200
@@ -1,5 +1,7 @@
 package digilib.conf;
 
+import java.util.EnumSet;
+
 /*
  * #%L
  * DigilibRequest.java
@@ -73,7 +75,6 @@
      * ServletRequest. All undefined parameters are set to default values.
      * 
      * @param request
-     * @throws ImageOpException 
      */
     public DigilibServletRequest(HttpServletRequest request) {
         super();
@@ -86,7 +87,7 @@
      * ServletRequest. All undefined parameters are set to default values.
      * 
      * @param request
-     * @throws ImageOpException 
+     * @param config
      */
     public DigilibServletRequest(HttpServletRequest request, DigilibConfiguration config) {
         super(config);
@@ -94,58 +95,34 @@
         initOptions();
     }
 
+    /**
+     * Creates a new instance of DigilibRequest with parameters from a
+     * ServletRequest. All undefined parameters are set to default values.
+     * 
+     * @param request
+     * @param config
+     * @param parsingOptions
+     */
+	public DigilibServletRequest(HttpServletRequest request, DigilibConfiguration config,
+			EnumSet<ParsingOption> parsingOptions) {
+        super(config);
+        this.parsingOptions = parsingOptions;
+        setWithRequest(request);
+        initOptions();
+    }
+
     /* (non-Javadoc)
      * @see digilib.conf.DigilibRequest#initParams()
      * Define and set up parameters with default values.
      */
     @Override
     protected void initParams() {
-        // TODO: check if we can call super.initParams()
+        super.initParams();
         /*
-         * Definition of parameters and default values. Parameter of type 's'
+         * Definition of additional parameters and default values. Parameter of type 's'
          * are for the servlet.
          */
 
-        // url of the page/document (second part)
-        newParameter("fn", "", null, 's');
-        // page number
-        newParameter("pn", new Integer(1), null, 's');
-        // width of client in pixels
-        newParameter("dw", new Integer(0), null, 's');
-        // height of client in pixels
-        newParameter("dh", new Integer(0), null, 's');
-        // left edge of image (float from 0 to 1)
-        newParameter("wx", new Float(0), null, 's');
-        // top edge in image (float from 0 to 1)
-        newParameter("wy", new Float(0), null, 's');
-        // width of image (float from 0 to 1)
-        newParameter("ww", new Float(1), null, 's');
-        // height of image (float from 0 to 1)
-        newParameter("wh", new Float(1), null, 's');
-        // scale factor
-        newParameter("ws", new Float(1), null, 's');
-        // special options like 'fit' for gifs
-        newParameter("mo", this.options, null, 's');
-        // rotation angle (degree)
-        newParameter("rot", new Float(0), null, 's');
-        // contrast enhancement factor
-        newParameter("cont", new Float(0), null, 's');
-        // brightness enhancement factor
-        newParameter("brgt", new Float(0), null, 's');
-        // color multiplicative factors
-        newParameter("rgbm", "0/0/0", null, 's');
-        // color additive factors
-        newParameter("rgba", "0/0/0", null, 's');
-        // display dpi resolution (total)
-        newParameter("ddpi", new Float(0), null, 's');
-        // display dpi X resolution
-        newParameter("ddpix", new Float(0), null, 's');
-        // display dpi Y resolution
-        newParameter("ddpiy", new Float(0), null, 's');
-        // scale factor for mo=ascale
-        newParameter("scale", new Float(1), null, 's');
-        // color conversion operation
-        newParameter("colop", "", null, 's');
         // OpenID Connect ID token
         newParameter("id_token", "", null, 's');
 
@@ -154,39 +131,12 @@
          * but are for the servlets or JSPs internal use.
          */
 
-        // url of the page/document (first part, may be empty)
-        newParameter("request.path", "", null, 'i');
-        // base URL (from http:// to below /servlet)
-        newParameter("base.url", null, null, 'i');
         // DocuImage instance for this request
         newParameter("docu.image", image, null, 'i');
         image = null;
         // HttpServletRequest for this request
         newParameter("servlet.request", servletRequest, null, 'i');
         servletRequest = null;
-
-        /*
-         * Parameters of type 'c' are for the clients use
-         */
-
-        // "real" filename
-        newParameter("img.fn", "", null, 'c');
-        // image dpi x
-        newParameter("img.dpix", new Integer(0), null, 'c');
-        // image dpi y
-        newParameter("img.dpiy", new Integer(0), null, 'c');
-        // hires image size x
-        newParameter("img.pix_x", new Integer(0), null, 'c');
-        // hires image size y
-        newParameter("img.pix_y", new Integer(0), null, 'c');
-        
-        /*
-         * set local variables from config
-         */
-        if (config != null) {
-            iiifPrefix = config.getAsString("iiif-prefix");
-            iiifSlashReplacement = config.getAsString("iiif-slash-replacement");
-        }
     }
 
     /*
@@ -212,7 +162,9 @@
         setValue("servlet.request", request);
         // request path (after servlet, before "?")
         String path = request.getPathInfo();
-        // decide if its IIIF API
+        /*
+         * is it IIIF API?
+         */
         if (path != null && path.startsWith(iiifPrefix, 1)) {
             // for IIIF we need the undecoded path :-(
             String uri = request.getRequestURI();
@@ -228,7 +180,9 @@
                 setValue("dw", -1);
             }
         } else {
-            // decide if it's old-style or new-style digilib
+            /*
+             * is it old-style or new-style digilib?
+             */
             String qs = ((HttpServletRequest) request).getQueryString();
             if (qs != null) {
                 if (qs.indexOf("&amp;") > -1) {
--- a/servlet/src/main/java/digilib/servlet/ServletOps.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/servlet/src/main/java/digilib/servlet/ServletOps.java	Thu Jun 01 15:06:02 2017 +0200
@@ -41,6 +41,7 @@
 
 import org.apache.log4j.Logger;
 
+import digilib.conf.DigilibServletConfiguration;
 import digilib.conf.DigilibServletRequest;
 import digilib.image.DocuImage;
 import digilib.image.ImageOpException;
@@ -52,16 +53,39 @@
 
 public class ServletOps {
 
-    private static Logger logger = Logger.getLogger("servlet.op");
+    protected static Logger logger = Logger.getLogger("servlet.op");
+    
+    protected static DigilibServletConfiguration dlConfig;
+    
+    /** set CORS header ACAO* for info requests */
+    protected static boolean corsForInfoRequests = true;
+
+    /** set CORS header ACAO* for image requests */
+    protected static boolean corsForImageRequests = true;
 
     /**
+	 * @return the dlConfig
+	 */
+	public static DigilibServletConfiguration getDlConfig() {
+		return dlConfig;
+	}
+
+	/**
+	 * @param dlConfig the dlConfig to set
+	 */
+	public static void setDlConfig(DigilibServletConfiguration dlConfig) {
+		ServletOps.dlConfig = dlConfig;
+		corsForInfoRequests = dlConfig.getAsBoolean("iiif-info-cors");
+		corsForImageRequests = dlConfig.getAsBoolean("iiif-image-cors");
+	}
+
+	/**
      * convert a string with a list of pathnames into an array of strings using
      * the system's path separator string
      */
     public static String[] getPathArray(String paths) {
         // split list into directories
-        StringTokenizer dirs = new StringTokenizer(paths,
-                java.io.File.pathSeparator);
+		StringTokenizer dirs = new StringTokenizer(paths, java.io.File.pathSeparator);
         int n = dirs.countTokens();
         if (n < 1) {
             return null;
@@ -225,6 +249,7 @@
      * The local file is copied to the <code>OutputStream</code> of the
      * <code>ServletResponse</code>. If mt is null then the mime-type is
      * auto-detected with mimeForFile.
+     * 
      * @param f
      *            Image file to be sent.
      * @param mt
@@ -246,6 +271,9 @@
     		logger.error("No response!");
     		return;
     	}
+    	/*
+    	 * set content-type
+    	 */
         if (mt == null) {
             // auto-detect mime-type
             mt = FileOps.mimeForFile(f);
@@ -254,7 +282,6 @@
             }
         }
         response.setContentType(mt);
-        // open file
         if (mt.startsWith("application")) {
             if (name == null) {
                 // no download name -- use filename
@@ -262,7 +289,19 @@
             }
             response.addHeader("Content-Disposition", "attachment; filename=\""+name+"\"");
         }
-        FileInputStream inFile = null;
+
+        /*
+		 * set CORS header ACAO "*" for image response
+		 */
+		if (corsForImageRequests) {
+			// TODO: would be nice to check request for Origin header
+			response.setHeader("Access-Control-Allow-Origin", "*");
+		}
+
+        /*
+         * open file
+         */
+		FileInputStream inFile = null;
         try {
             inFile = new FileInputStream(f);
             OutputStream outStream = response.getOutputStream();
@@ -313,9 +352,8 @@
      * @throws ImageOpException
      * @throws ServletException Exception on sending data.
      */
-    public static void sendImage(DocuImage img, String mimeType,
-            HttpServletResponse response, Logger logger) throws ImageOpException,
-            ServletException {
+	public static void sendImage(DocuImage img, String mimeType, HttpServletResponse response, Logger logger)
+			throws ImageOpException, ServletException {
     	if (response == null) {
     		logger.error("No response!");
     		return;
@@ -342,6 +380,7 @@
             }
             // set the content type
             response.setContentType(mimeType);
+            // check content type
             String respType = response.getContentType();
             if (! mimeType.equals(respType)) {
             	// this shouldn't happen
@@ -351,6 +390,15 @@
             	return;
             }
             
+
+            /*
+    		 * set CORS header ACAO "*" for image response
+    		 */
+    		if (corsForImageRequests) {
+    			// TODO: would be nice to check request for Origin header
+    			response.setHeader("Access-Control-Allow-Origin", "*");
+    		}
+
             /*
              * write the image
              */
@@ -375,7 +423,8 @@
      * @throws ServletException
      * @see <a href="http://www-sul.stanford.edu/iiif/image-api/1.1/#info">IIIF Image Information Request</a>
      */
-    public static void sendIiifInfo(DigilibServletRequest dlReq, HttpServletResponse response, Logger logger) throws ServletException {
+	public static void sendIiifInfo(DigilibServletRequest dlReq, HttpServletResponse response, Logger logger)
+			throws ServletException {
         if (response == null) {
             logger.error("No response!");
             return;
@@ -419,7 +468,7 @@
             /*
              * set CORS header ACAO "*" for info response as per IIIF spec
              */
-            if (dlReq.getDigilibConfig().getAsBoolean("iiif-info-cors")) {
+            if (corsForInfoRequests) {
                 String origin = dlReq.getServletRequest().getHeader("Origin");
                 if (origin != null) {
                     response.setHeader("Access-Control-Allow-Origin", "*");
@@ -427,7 +476,7 @@
             }
             
             PrintWriter writer;
-            if (dlReq.getDigilibConfig().getAsString("iiif-api-version").startsWith("2.")) {
+            if (dlConfig.getAsString("iiif-api-version").startsWith("2.")) {
                 /*
                  * IIIF Image API version 2 image information
                  */
--- a/servlet2/src/main/java/digilib/servlet/Scaler.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/servlet2/src/main/java/digilib/servlet/Scaler.java	Thu Jun 01 15:06:02 2017 +0200
@@ -147,6 +147,9 @@
         // Executor
         imageJobCenter = (DigilibJobCenter<DocuImage>) dlConfig.getValue("servlet.worker.imageexecutor");
 
+        // configure ServletOps
+        ServletOps.setDlConfig(dlConfig);
+        
         denyImgFile = ServletOps.getFile(dlConfig.getAsFile("denied-image"), context);
         errorImgFile = ServletOps.getFile(dlConfig.getAsFile("error-image"), context);
         notfoundImgFile = ServletOps.getFile(dlConfig.getAsFile("notfound-image"), context);
--- a/servlet2/src/main/java/digilib/servlet/ScalerNoThread.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/servlet2/src/main/java/digilib/servlet/ScalerNoThread.java	Thu Jun 01 15:06:02 2017 +0200
@@ -130,6 +130,9 @@
         // DocuDirCache instance
         dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
 
+        // configure ServletOps
+        ServletOps.setDlConfig(dlConfig);
+        
         denyImgFile = ServletOps.getFile((File) dlConfig.getValue("denied-image"), context);
         errorImgFile = ServletOps.getFile((File) dlConfig.getValue("error-image"), context);
         notfoundImgFile = ServletOps.getFile((File) dlConfig.getValue("notfound-image"), context);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet3/pom.xml.orig	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,39 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>digilib</artifactId>
+    <groupId>digilib</groupId>
+    <version>2.3.1</version>
+  </parent>
+  <artifactId>digilib-servlet3</artifactId>
+  <name>digilib-servlet3</name>
+  <build>
+  	<pluginManagement>
+  		<plugins>
+  			<plugin>
+  				<groupId>org.apache.maven.plugins</groupId>
+  				<artifactId>maven-compiler-plugin</artifactId>
+                <version>3.3</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target> 
+                </configuration>
+  			</plugin>
+  		</plugins>
+  	</pluginManagement>
+  </build>
+  <dependencies>
+  	<dependency>
+  		<groupId>org.mortbay.jetty</groupId>
+  		<artifactId>servlet-api</artifactId>
+  		<version>3.0.20100224</version>
+  		<type>jar</type>
+  		<scope>provided</scope>
+  	</dependency>
+  	<dependency>
+  		<groupId>digilib</groupId>
+  		<artifactId>digilib-servlet</artifactId>
+  	</dependency>
+  </dependencies>
+  <description>digilib servlet components using asynchronous servlet API.</description>
+</project>
\ No newline at end of file
--- a/servlet3/src/main/java/digilib/servlet/Scaler.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/servlet3/src/main/java/digilib/servlet/Scaler.java	Thu Jun 01 15:06:02 2017 +0200
@@ -42,7 +42,6 @@
 
 import digilib.auth.AuthOpException;
 import digilib.auth.AuthzOps;
-import digilib.conf.DigilibConfiguration;
 import digilib.conf.DigilibOption;
 import digilib.conf.DigilibServlet3Configuration;
 import digilib.conf.DigilibServletConfiguration;
@@ -104,7 +103,7 @@
     protected boolean sendFileAllowed = true;
 
     /** DigilibConfiguration instance */
-    protected DigilibConfiguration dlConfig;
+    protected DigilibServletConfiguration dlConfig;
 
     /** use authorization database */
     protected boolean useAuthorization = false;
@@ -142,11 +141,14 @@
         authzOp = (AuthzOps) dlConfig.getValue(DigilibServletConfiguration.AUTHZ_OP_KEY);
 
         // DocuDirCache instance
-        dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+        dirCache = (DocuDirCache) dlConfig.getValue(DigilibServletConfiguration.DIR_CACHE_KEY);
 
         // Executor
         imageJobCenter = (DigilibJobCenter<DocuImage>) dlConfig.getValue("servlet.worker.imageexecutor");
 
+        // configure ServletOps
+        ServletOps.setDlConfig(dlConfig);
+        
         denyImgFile = ServletOps.getFile(dlConfig.getAsFile("denied-image"), context);
         errorImgFile = ServletOps.getFile(dlConfig.getAsFile("error-image"), context);
         notfoundImgFile = ServletOps.getFile(dlConfig.getAsFile("notfound-image"), context);
@@ -260,8 +262,14 @@
                 return;
             }
             if (dlRequest.hasOption(DigilibOption.redirect_info)) {
+            	StringBuffer url = request.getRequestURL();
+            	if (url.toString().endsWith("/")) {
+            		url.append("info.json");
+            	} else {
+            		url.append("/info.json");
+            	}
                 // TODO: the redirect should have code 303
-                response.sendRedirect("info.json");
+                response.sendRedirect(url.toString());
                 return;
             }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/text/pom.xml.orig	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,72 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<artifactId>digilib</artifactId>
+		<groupId>digilib</groupId>
+		<version>2.3.1</version>
+	</parent>
+	<artifactId>digilib-text</artifactId>
+	<name>digilib-text</name>
+	<dependencies>
+		<dependency>
+			<groupId>digilib</groupId>
+			<artifactId>digilib-common</artifactId>
+			<type>jar</type>
+			<scope>compile</scope>
+		</dependency>
+	</dependencies>
+	<description>The Digital Image Library - text (plain or XML) serving servlet</description>
+	<url>http://digilib.sourceforge.net</url>
+	<profiles>
+		<profile>
+			<id>servlet2</id>
+			<activation>
+				<activeByDefault>true</activeByDefault>
+				<property>
+					<name>servletapi</name>
+					<value>2</value>
+				</property>
+			</activation>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-servlet2</artifactId>
+					<type>jar</type>
+					<scope>provided</scope>
+				</dependency>
+				<dependency>
+					<groupId>javax.servlet</groupId>
+					<artifactId>servlet-api</artifactId>
+					<version>2.3</version>
+					<type>jar</type>
+					<scope>provided</scope>
+				</dependency>
+			</dependencies>
+		</profile>
+		<profile>
+			<id>servlet3</id>
+			<activation>
+				<property>
+					<name>servletapi</name>
+					<value>3</value>
+				</property>
+			</activation>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-servlet3</artifactId>
+					<type>jar</type>
+					<scope>provided</scope>
+				</dependency>
+				<dependency>
+					<groupId>org.mortbay.jetty</groupId>
+					<artifactId>servlet-api</artifactId>
+					<version>3.0.20100224</version>
+					<type>jar</type>
+					<scope>provided</scope>
+				</dependency>
+			</dependencies>
+		</profile>
+	</profiles>
+</project>
\ No newline at end of file
--- a/text/src/main/java/digilib/servlet/Texter.java	Wed Mar 08 13:12:01 2017 +0100
+++ b/text/src/main/java/digilib/servlet/Texter.java	Thu Jun 01 15:06:02 2017 +0200
@@ -62,28 +62,25 @@
 	public static String tlVersion = TextServletConfiguration.getClassVersion();
 
 	/** DigilibConfiguration instance */
-	DigilibServletConfiguration dlConfig = null;
+	protected DigilibServletConfiguration dlConfig = null;
 
 	/** general logger */
-	Logger logger = Logger.getLogger("digilib.texter");
+	protected Logger logger = Logger.getLogger("digilib.texter");
 
     /** logger for accounting requests */
     protected static Logger accountlog = Logger.getLogger("account.texter.request");
 
 	/** FileOps instance */
-	FileOps fileOp;
+    protected FileOps fileOp;
 
 	/** AuthOps instance */
-	AuthzOps authzOp;
-
-	/** ServletOps instance */
-	ServletOps servletOp;
+    protected AuthzOps authzOp;
 
 	/** DocuDirCache instance */
-	DocuDirCache dirCache;
+    protected DocuDirCache dirCache;
 
 	/** use authentication */
-	boolean useAuthorization = false;
+    protected boolean useAuthorization = false;
 
 	/*
 	 * (non-Javadoc)
@@ -113,6 +110,8 @@
 		authzOp = (AuthzOps) dlConfig.getValue(DigilibServletConfiguration.AUTHZ_OP_KEY);
 		// DocuDirCache instance
 		dirCache = (DocuDirCache) dlConfig.getValue(TextServletConfiguration.TEXT_DIR_CACHE_KEY);
+        // configure ServletOps
+        ServletOps.setDlConfig(dlConfig);        
 	}
 
 	/*
@@ -192,7 +191,7 @@
 	 * @return The wanted Textfile or null if there wasn't a file.
 	 */
 
-	private TextFile getTextFile(DigilibServletRequest dlRequest, String subDirectory) {
+	protected TextFile getTextFile(DigilibServletRequest dlRequest, String subDirectory) {
 		String loadPathName = dlRequest.getFilePath() + subDirectory;
 		// find the file(set)
 		return (TextFile) dirCache.getFile(loadPathName, dlRequest.getAsInt("pn"));
--- a/webapp/pom.xml	Wed Mar 08 13:12:01 2017 +0100
+++ b/webapp/pom.xml	Thu Jun 01 15:06:02 2017 +0200
@@ -276,6 +276,36 @@
 				</dependency>
 			</dependencies>
 		</profile>
+        <profile>
+            <id>iiif-presentation</id>
+            <!-- IIIF presentation servlet uses servlet3 and has a web.xml -->
+            <dependencies>
+                <dependency>
+                    <groupId>digilib</groupId>
+                    <artifactId>digilib-iiif-presentation</artifactId>
+                    <type>jar</type>
+                    <scope>compile</scope>
+                </dependency>
+                <dependency>
+                    <groupId>digilib</groupId>
+                    <artifactId>digilib-servlet3</artifactId>
+                    <type>jar</type>
+                    <scope>compile</scope>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-war-plugin</artifactId>
+                        <configuration>
+                            <webXml>${basedir}/src/main/webapp/WEB-INF/web-iiif-pres.xml</webXml>
+                            <classifier>srv3p</classifier>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
 		<profile>
 			<id>codec-jai</id>
 			<dependencies>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/pom.xml.orig	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,204 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<artifactId>digilib</artifactId>
+		<groupId>digilib</groupId>
+		<version>2.3.7</version>
+	</parent>
+	<artifactId>digilib-webapp</artifactId>
+	<name>digilib-webapp</name>
+	<description>The Digital Image Library - web application server and HTML and JS clients.</description>
+	<url>http://digilib.sourceforge.net</url>
+	<packaging>war</packaging>
+	
+	<properties>
+        <skipTests>true</skipTests>
+    </properties>
+
+	<build>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-war-plugin</artifactId>
+					<version>2.6</version>
+				</plugin>
+				<plugin>
+					<groupId>org.codehaus.mojo</groupId>
+					<artifactId>license-maven-plugin</artifactId>
+					<version>1.4</version>
+					<configuration>
+						<includes>
+							<include>**/*digilib*.js</include>
+							<include>**/*.jsp</include>
+						</includes>
+					</configuration>
+				</plugin>
+		        <plugin>
+			        <groupId>org.apache.maven.plugins</groupId>
+			        <artifactId>maven-surefire-plugin</artifactId>
+			        <version>2.19</version>
+			        <configuration>
+			            <skip>${skipTests}</skip>
+			        </configuration>
+			    </plugin>
+        	</plugins>
+		</pluginManagement>
+	</build>
+	<profiles>
+		<profile>
+			<id>servlet2</id>
+			<activation>
+				<property>
+					<name>servletapi</name>
+					<value>2</value>
+				</property>
+			</activation>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-servlet2</artifactId>
+					<type>jar</type>
+					<scope>compile</scope>
+				</dependency>
+			</dependencies>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-war-plugin</artifactId>
+						<configuration>
+							<webXml>${basedir}/src/main/webapp/WEB-INF/web-2.4.xml</webXml>
+							<classifier>srv2</classifier>
+						</configuration>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+		<profile>
+			<id>servlet3</id>
+			<activation>
+				<activeByDefault>true</activeByDefault>
+				<property>
+					<name>servletapi</name>
+					<value>3</value>
+				</property>
+			</activation>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-servlet3</artifactId>
+					<type>jar</type>
+					<scope>compile</scope>
+				</dependency>
+			</dependencies>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-war-plugin</artifactId>
+						<configuration>
+							<webXml>${basedir}/src/main/webapp/WEB-INF/web-3.0.xml</webXml>
+							<classifier>srv3</classifier>
+						</configuration>
+					</plugin>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-compiler-plugin</artifactId>
+						<configuration>
+							<source>1.7</source>
+							<target>1.7</target>
+						</configuration>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+		<profile>
+			<id>pdf</id>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-pdf</artifactId>
+					<type>jar</type>
+					<scope>compile</scope>
+				</dependency>
+			</dependencies>
+		</profile>
+		<profile>
+			<id>text</id>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-text</artifactId>
+					<type>jar</type>
+					<scope>compile</scope>
+				</dependency>
+			</dependencies>
+		</profile>
+		<profile>
+			<id>codec-jai</id>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-common-jai</artifactId>
+					<type>jar</type>
+					<scope>compile</scope>
+				</dependency>
+			</dependencies>
+		</profile>
+		<profile>
+			<id>codec-imagej</id>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-common-imagej</artifactId>
+					<type>jar</type>
+					<scope>compile</scope>
+				</dependency>
+			</dependencies>
+		</profile>
+		<profile>
+			<id>codec-bioformats</id>
+			<dependencies>
+				<dependency>
+					<groupId>digilib</groupId>
+					<artifactId>digilib-common-bioformats</artifactId>
+					<type>jar</type>
+					<scope>compile</scope>
+				</dependency>
+			</dependencies>
+		</profile>
+        <profile>
+            <id>cors-filter</id>
+            <!--  external servlet filter to add CORS headers. enable in web.xml -->
+            <dependencies>
+                <dependency>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-servlets</artifactId>
+                    <version>9.2.13.v20150730</version>
+                </dependency>
+            </dependencies>
+        </profile>
+	</profiles>
+	<dependencies>
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-servlet</artifactId>
+            <version>9.2.13.v20150730</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse.jetty</groupId>
+			<artifactId>jetty-http</artifactId>
+			<version>9.2.13.v20150730</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.12</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+</project>
--- a/webapp/src/main/webapp/WEB-INF/web-3.0.xml	Wed Mar 08 13:12:01 2017 +0100
+++ b/webapp/src/main/webapp/WEB-INF/web-3.0.xml	Thu Jun 01 15:06:02 2017 +0200
@@ -50,4 +50,6 @@
             /Scaler/*
         </url-pattern>
   </servlet-mapping>
+  
+  
 </web-app>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/WEB-INF/web-iiif-pres.xml	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app
+        xmlns="http://java.sun.com/xml/ns/javaee"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+        version="3.0">
+        
+  <!-- General description of your web application -->
+  <display-name>
+        digilib
+  </display-name>
+  <description>
+        This is the web frontend of the Digital Document Library.
+  </description>
+  <!-- The Intialisation Listener (also configured by annotation) -->
+  <listener>
+        <listener-class>
+            digilib.conf.DigilibServlet3Configuration
+        </listener-class>
+  </listener>
+  <!-- The Scaler servlet (also configured by annotation) -->
+  <servlet>
+        <servlet-name>
+            Scaler
+        </servlet-name>
+        <servlet-class>
+            digilib.servlet.Scaler
+        </servlet-class>
+        <!-- Load this servlet at server startup time -->
+        <load-on-startup>
+            5
+        </load-on-startup>
+        <!-- yes we do use async, Jetty! -->
+        <async-supported>true</async-supported>
+  </servlet>
+  <!-- The mapping for the Scaler servlet -->
+  <servlet-mapping>
+        <servlet-name>
+            Scaler
+        </servlet-name>
+        <url-pattern>
+            /servlet/Scaler/*
+        </url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+        <servlet-name>
+            Scaler
+        </servlet-name>
+        <url-pattern>
+            /Scaler/*
+        </url-pattern>
+  </servlet-mapping>
+  
+    <!-- The Manifest servlet -->
+    <servlet>
+        <servlet-name>Manifester</servlet-name>
+        <servlet-class>digilib.servlet.Manifester</servlet-class>
+    </servlet>
+    <!-- The Intialisation Listener -->
+    <listener>
+        <listener-class>
+            digilib.conf.ManifestServletConfiguration
+        </listener-class>
+    </listener>
+    <!-- The mapping for the Manifest servlet -->
+    <servlet-mapping>
+        <servlet-name>Manifester</servlet-name>
+        <url-pattern>/servlet/Manifester/*</url-pattern>
+    </servlet-mapping>
+
+
+  
+</web-app>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/digilib-auth.html.orig	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,61 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+        <meta name="viewport" content="initial-scale=1.0"/>
+        <title>Digilib jQuery: fullscreen</title>
+
+        <style type="text/css">
+            body {
+                 background: silver;
+            }
+        </style>
+
+        <script type="text/javascript" src="jquery.js"></script>
+        <script type="text/javascript" src="jquery.cookie.js"></script>
+
+        <!-- 
+        <script type="text/javascript" src="jquery.digilib-auth.min.js"></script>
+        <link rel="stylesheet" type="text/css" href="jquery.digilib-auth.min.css" />
+        -->
+        
+        <script type="text/javascript" src="jquery.digilib.js"></script>
+        <script type="text/javascript" src="jquery.digilib.geometry.js"></script>
+        <script type="text/javascript" src="jquery.digilib.arrows.js"></script>
+        <script type="text/javascript" src="jquery.range.js"></script>
+        <link rel="stylesheet" type="text/css" href="jquery.range.css" />
+        <script type="text/javascript" src="jquery.digilib.buttons.js"></script>
+        <script type="text/javascript" src="jquery.digilib.dialogs.js"></script>
+        <script type="text/javascript" src="jquery.digilib.sliders.js"></script>
+        <script type="text/javascript" src="jquery.digilib.birdseye.js"></script>
+        <script type="text/javascript" src="jquery.digilib.marks.js"></script>
+        <script type="text/javascript" src="jquery.digilib.regions.js"></script>
+        <script type="text/javascript" src="jquery.digilib.oauth.js"></script>
+        <link rel="stylesheet" type="text/css" href="jquery.digilib.css" />
+        <link rel="stylesheet" type="text/css" href="jquery.digilib.buttons-full-32-sprite.css" />
+        
+
+        <script type="text/javascript">
+            $(document).ready(function(){
+                var opts = {
+                    //authServerUrl : 'http://localhost:18080/ldap-openid-connect-server/authorize',
+                    //authClientId : 'client',
+                    authServerUrl : 'https://id.mpiwg-berlin.mpg.de/openid/authorize',
+                    authClientId : 'digilib-rc-local',
+                    authOnErrorMode : true
+                };
+                var $div = $('div#digilib');
+                $div.digilib(opts);
+            });
+
+        </script>
+    </head>
+
+    <body>
+        <div id="digilib">
+            <p>digilib doesn't work! Please switch on Javascript or notify the server administrator!</p>
+            <img src="http://digilib.sourceforge.net/images/digilib-logo-big.png" />
+        </div>
+    </body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/digilib.html.orig	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+        <meta name="viewport" content="initial-scale=1.0"/>
+        <title>Digilib jQuery: fullscreen</title>
+
+        <style type="text/css">
+            body {
+                 background: silver;
+            }
+        </style>
+
+        <script type="text/javascript" src="jquery.min.js"></script>
+        <script type="text/javascript" src="jquery.cookie-range.min.js"></script>
+        <script type="text/javascript" src="jquery.digilib-basic.min.js"></script>
+        <link rel="stylesheet" type="text/css" href="jquery.digilib-basic.css" />
+
+        <script type="text/javascript">
+            $(document).ready(function(){
+                var opts = {
+                    interactionMode : 'fullscreen',
+                    showRegionNumbers : true
+                    };
+                var $div = $('div#digilib');
+                $div.digilib(opts);
+            });
+
+        </script>
+    </head>
+
+    <body>
+        <div id="digilib">
+            <p>digilib doesn't work! Please switch on Javascript or notify the server administrator!</p>
+            <img src="http://digilib.sourceforge.net/images/digilib-logo-big.png" />
+        </div>
+    </body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-ann.css	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-ann.css
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-ann.js	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-ann.js
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-ann.min.css	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-ann.min.css
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-ann.min.js	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-ann.min.js
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-ann.min.js.map	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-ann.min.js.map
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-auth.css	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-auth.css
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-auth.js	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-auth.js
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-auth.min.css	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-auth.min.css
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webapp/src/main/webapp/jquery/jquery.digilib-auth.min.js	Thu Jun 01 15:06:02 2017 +0200
@@ -0,0 +1,1 @@
+../../../../target/digilib-webapp-2.5-SNAPSHOT/jquery/jquery.digilib-auth.min.js
\ No newline at end of file