changeset 8187:3bb1c62ad732

Moved package org.dive4elements.river.utils to org.dive4elements.river.backend.utils.
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 04 Sep 2014 15:03:25 +0200
parents a1ceacf15d3a
children 096a7a710500 fcc1ffbc2ea6
files backend/src/main/java/org/dive4elements/river/backend/utils/DBCPConnectionProvider.java backend/src/main/java/org/dive4elements/river/backend/utils/DateGuesser.java backend/src/main/java/org/dive4elements/river/backend/utils/DateUtil.java backend/src/main/java/org/dive4elements/river/backend/utils/DouglasPeuker.java backend/src/main/java/org/dive4elements/river/backend/utils/EpsilonComparator.java backend/src/main/java/org/dive4elements/river/backend/utils/StringUtil.java backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java backend/src/main/java/org/dive4elements/river/importer/Importer.java backend/src/main/java/org/dive4elements/river/importer/ImporterSession.java backend/src/main/java/org/dive4elements/river/importer/parsers/AbstractSedimentLoadParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/BedHeightParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/DA50Parser.java backend/src/main/java/org/dive4elements/river/importer/parsers/DA66Parser.java backend/src/main/java/org/dive4elements/river/importer/parsers/FlowVelocityModelParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/NameAndTimeInterval.java backend/src/main/java/org/dive4elements/river/importer/parsers/PorosityParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/SQRelationParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/W80CSVParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/W80Parser.java backend/src/main/java/org/dive4elements/river/importer/parsers/WaterlevelDifferencesParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/WaterlevelParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/WstParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/tim/TIMParser.java backend/src/main/java/org/dive4elements/river/utils/DBCPConnectionProvider.java backend/src/main/java/org/dive4elements/river/utils/DateGuesser.java backend/src/main/java/org/dive4elements/river/utils/DateUtil.java backend/src/main/java/org/dive4elements/river/utils/DouglasPeuker.java backend/src/main/java/org/dive4elements/river/utils/EpsilonComparator.java backend/src/main/java/org/dive4elements/river/utils/StringUtil.java
diffstat 29 files changed, 1532 insertions(+), 1532 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend/src/main/java/org/dive4elements/river/backend/utils/DBCPConnectionProvider.java	Thu Sep 04 15:03:25 2014 +0200
@@ -0,0 +1,261 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.dive4elements.river.backend.utils;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Map;
+import java.util.Collections;
+import java.util.StringTokenizer;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.dbcp.BasicDataSourceFactory;
+
+import org.apache.log4j.Logger;
+
+import org.hibernate.HibernateException;
+
+import org.hibernate.connection.ConnectionProviderFactory;
+import org.hibernate.connection.ConnectionProvider;
+
+import org.hibernate.cfg.Environment;
+
+/**
+ * <p>A connection provider that uses an Apache commons DBCP connection pool.</p>
+ *
+ * <p>To use this connection provider set:<br>
+ * <code>hibernate.connection.provider_class&nbsp;org.hibernate.connection.DBCPConnectionProvider</code></p>
+ *
+ * <pre>Supported Hibernate properties:
+ *   hibernate.connection.driver_class
+ *   hibernate.connection.url
+ *   hibernate.connection.username
+ *   hibernate.connection.password
+ *   hibernate.connection.isolation
+ *   hibernate.connection.autocommit
+ *   hibernate.connection.pool_size
+ *   hibernate.connection (JDBC driver properties)</pre>
+ * <br>
+ * All DBCP properties are also supported by using the hibernate.dbcp prefix.
+ * A complete list can be found on the DBCP configuration page:
+ * <a href="http://jakarta.apache.org/commons/dbcp/configuration.html">http://jakarta.apache.org/commons/dbcp/configuration.html</a>.
+ * <br>
+ * <pre>Example:
+ *   hibernate.connection.provider_class org.hibernate.connection.DBCPConnectionProvider
+ *   hibernate.connection.driver_class org.hsqldb.jdbcDriver
+ *   hibernate.connection.username sa
+ *   hibernate.connection.password
+ *   hibernate.connection.url jdbc:hsqldb:test
+ *   hibernate.connection.pool_size 20
+ *   hibernate.dbcp.initialSize 10
+ *   hibernate.dbcp.maxWait 3000
+ *   hibernate.dbcp.validationQuery select 1 from dual</pre>
+ *
+ * <p>More information about configuring/using DBCP can be found on the
+ * <a href="http://jakarta.apache.org/commons/dbcp/">DBCP website</a>.
+ * There you will also find the DBCP wiki, mailing lists, issue tracking
+ * and other support facilities</p>
+ *
+ * @see org.hibernate.connection.ConnectionProvider
+ * @author Dirk Verbeeck
+ */
+public class DBCPConnectionProvider
+implements   ConnectionProvider
+{
+    private static Logger log = Logger.getLogger(DBCPConnectionProvider.class);
+
+    private static final String PREFIX = "hibernate.dbcp.";
+
+    private BasicDataSource ds;
+
+    // Old Environment property for backward-compatibility
+    // (property removed in Hibernate3)
+    private static final String DBCP_PS_MAXACTIVE =
+        "hibernate.dbcp.ps.maxActive";
+
+    // Property doesn't exists in Hibernate2
+    private static final String AUTOCOMMIT =
+        "hibernate.connection.autocommit";
+
+    public void configure(Properties props) throws HibernateException {
+        try {
+            log.debug("Configure DBCPConnectionProvider");
+
+            // DBCP properties used to create the BasicDataSource
+            Properties dbcpProperties = new Properties();
+
+            // DriverClass & url
+            String jdbcDriverClass = props.getProperty(Environment.DRIVER);
+            String jdbcUrl = props.getProperty(Environment.URL);
+            dbcpProperties.put("driverClassName", jdbcDriverClass);
+            dbcpProperties.put("url", jdbcUrl);
+
+            // Username / password
+            String username = props.getProperty(Environment.USER);
+            String password = props.getProperty(Environment.PASS);
+            dbcpProperties.put("username", username);
+            dbcpProperties.put("password", password);
+
+            // Isolation level
+            String isolationLevel = props.getProperty(Environment.ISOLATION);
+            if (isolationLevel != null
+            && (isolationLevel = isolationLevel.trim()).length() > 0) {
+                dbcpProperties.put("defaultTransactionIsolation", isolationLevel);
+            }
+
+            // Turn off autocommit (unless autocommit property is set)
+            String autocommit = props.getProperty(AUTOCOMMIT);
+            if (autocommit != null
+            && (autocommit = autocommit.trim()).length() > 0) {
+                dbcpProperties.put("defaultAutoCommit", autocommit);
+            } else {
+                dbcpProperties.put("defaultAutoCommit", String.valueOf(Boolean.FALSE));
+            }
+
+            // Pool size
+            String poolSize = props.getProperty(Environment.POOL_SIZE);
+            if (poolSize != null
+            && (poolSize = poolSize.trim()).length() > 0
+            && Integer.parseInt(poolSize) > 0)  {
+                dbcpProperties.put("maxActive", poolSize);
+            }
+
+            // Copy all "driver" properties into "connectionProperties"
+            Properties driverProps =
+                ConnectionProviderFactory.getConnectionProperties(props);
+
+            if (driverProps.size() > 0) {
+                StringBuilder connectionProperties = new StringBuilder();
+                for (Iterator iter = driverProps.entrySet().iterator();
+                    iter.hasNext();
+                ) {
+                    Map.Entry entry = (Map.Entry)iter.next();
+                    String    key   = (String)entry.getKey();
+                    String    value = (String)entry.getValue();
+                    connectionProperties
+                        .append(key)
+                        .append('=')
+                        .append(value);
+                    if (iter.hasNext()) {
+                        connectionProperties.append(';');
+                    }
+                }
+                dbcpProperties.put(
+                    "connectionProperties", connectionProperties.toString());
+            }
+
+            // Copy all DBCP properties removing the prefix
+            for (Iterator iter = props.entrySet().iterator() ; iter.hasNext() ;) {
+                Map.Entry entry = (Map.Entry)iter.next();
+                String    key   = (String)entry.getKey();
+                if (key.startsWith(PREFIX)) {
+                    String property = key.substring(PREFIX.length());
+                    String value    = (String)entry.getValue();
+                    dbcpProperties.put(property, value);
+                }
+            }
+
+            // Backward-compatibility
+            if (props.getProperty(DBCP_PS_MAXACTIVE) != null) {
+                dbcpProperties.put(
+                    "poolPreparedStatements",
+                    String.valueOf(Boolean.TRUE));
+                dbcpProperties.put(
+                    "maxOpenPreparedStatements",
+                    props.getProperty(DBCP_PS_MAXACTIVE));
+            }
+
+            // Some debug info
+            /* // commented out, because it leaks the password
+            if (log.isDebugEnabled()) {
+                log.debug("Creating a DBCP BasicDataSource" +
+                          " with the following DBCP factory properties:");
+                StringWriter sw = new StringWriter();
+                dbcpProperties.list(new PrintWriter(sw, true));
+                log.debug(sw.toString());
+            }
+            */
+
+            // Let the factory create the pool
+            ds = (BasicDataSource)BasicDataSourceFactory
+                .createDataSource(dbcpProperties);
+
+            // This needs to be done manually as it is somehow ignored
+            // by the BasicDataSourceFactory if you set it as a dbcpProperty
+            String connectionInitSqls = props.getProperty("connectionInitSqls");
+            if (connectionInitSqls != null) {
+                StringTokenizer tokenizer = new StringTokenizer(connectionInitSqls, ";");
+                ds.setConnectionInitSqls(Collections.list(tokenizer));
+            }
+            // The BasicDataSource has lazy initialization
+            // borrowing a connection will start the DataSource
+            // and make sure it is configured correctly.
+
+            // Connection conn = ds.getConnection();
+            // conn.close();
+        }
+        catch (Exception e) {
+            String message = "Could not create a DBCP pool";
+            log.fatal(message, e);
+            if (ds != null) {
+                BasicDataSource x = ds; ds = null;
+                try {
+                    x.close();
+                }
+                catch (SQLException sqle) {
+                }
+            }
+            throw new HibernateException(message, e);
+        }
+        log.debug("Configure DBCPConnectionProvider complete");
+    }
+
+    public Connection getConnection() throws SQLException {
+        return ds.getConnection();
+    }
+
+    public void closeConnection(Connection conn) throws SQLException {
+        conn.close();
+    }
+
+    public void close() throws HibernateException {
+        try {
+            if (ds != null) {
+                BasicDataSource x = ds; ds = null;
+                x.close();
+            }
+        }
+        catch (SQLException sqle) {
+            throw new HibernateException("Could not close DBCP pool", sqle);
+        }
+    }
+
+    public boolean supportsAggressiveRelease() {
+        return false;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend/src/main/java/org/dive4elements/river/backend/utils/DateGuesser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -0,0 +1,266 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.backend.utils;
+
+import java.util.Date;
+import java.util.Calendar;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public final class DateGuesser {
+    public static final String [] MONTH = {
+        "jan", "feb", "mrz", "apr", "mai", "jun",
+        "jul", "aug", "sep", "okt", "nov", "dez"
+    };
+
+    public static final int guessMonth(String s) {
+        s = s.toLowerCase();
+        for (int i = 0; i < MONTH.length; ++i)
+            if (MONTH[i].equals(s)) {
+                return i;
+            }
+        return -1;
+    }
+
+    public static final Pattern YYYY_MM_DD =
+        Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})$");
+
+    public static final Pattern DD_MM_YYYY =
+        Pattern.compile("^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{2,4})$");
+
+    public static final Pattern MMM_YYYY =
+        Pattern.compile("^(\\d{0,2})\\.?(\\w{3})\\.?(\\d{2,4})$");
+
+    public static final Pattern GARBAGE_YYYY =
+        Pattern.compile("^\\D*(\\d{2,4})$");
+
+    public static final Pattern YYYY_MM_DDThh_mm =
+        Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})$");
+
+    public static final Pattern YYYY_MM_DDThh_mm_ss =
+        Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})$");
+
+    public static final Pattern DD_MM_YYYYThh_mm =
+        Pattern.compile("^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{2,4})T(\\d{1,2}):(\\d{2})$");
+
+    public static final Pattern DD_MM_YYYYThh_mm_ss =
+        Pattern.compile("^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{2,4})T(\\d{1,2}):(\\d{2}):(\\d{2})$");
+
+    public static final Pattern DDMMYY =
+        Pattern.compile("^(\\d{2})(\\d{2})(\\d{2})$");
+
+    private DateGuesser() {
+    }
+
+    public static final int calendarMonth(String month) {
+        return calendarMonth(Integer.parseInt(month));
+    }
+
+    public static final int calendarMonth(int month) {
+        return Math.max(Math.min(month-1, 11), 0);
+    }
+
+    /**
+     * Guess date by trying all different patterns.
+     * Throws IllegalArgumentException if not able to guess.
+     * @param s The date to be guessed (e.g. 11.02.2001).
+     * @return the parsed Date.
+     */
+    public static Date guessDate(String s) {
+        if (s == null || (s = s.trim()).length() == 0) {
+            throw new IllegalArgumentException();
+        }
+
+        Matcher m;
+
+        m = YYYY_MM_DD.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String year  = m.group(1);
+            String month = m.group(2);
+            String day   = m.group(3);
+            cal.clear();
+            cal.set(
+                Integer.parseInt(year),
+                calendarMonth(month),
+                Integer.parseInt(day),
+                12, 0, 0);
+            return cal.getTime();
+        }
+
+        m = DD_MM_YYYY.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String year  = m.group(3);
+            String month = m.group(2);
+            String day   = m.group(1);
+            cal.clear();
+            cal.set(
+                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
+                calendarMonth(month),
+                Integer.parseInt(day),
+                12, 0, 0);
+            return cal.getTime();
+        }
+
+        m = MMM_YYYY.matcher(s);
+
+        if (m.matches()) {
+            int month = guessMonth(m.group(2));
+            if (month >= 0) {
+                Calendar cal = Calendar.getInstance();
+                String year = m.group(3);
+                String day  = m.group(1);
+                cal.clear();
+                cal.set(
+                    Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
+                    month,
+                    day.length() == 0 ? 15 : Integer.parseInt(day),
+                    12, 0, 0);
+                return cal.getTime();
+            }
+        }
+
+        m = YYYY_MM_DDThh_mm.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String year = m.group(1);
+            String month = m.group(2);
+            String day = m.group(3);
+            String hour = m.group(4);
+            String minute = m.group(5);
+            cal.clear();
+            cal.set(
+                Integer.parseInt(year),
+                calendarMonth(month),
+                Integer.parseInt(day),
+                Integer.parseInt(hour),
+                Integer.parseInt(minute),
+                0
+            );
+            return cal.getTime();
+        }
+
+        m = YYYY_MM_DDThh_mm_ss.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String year = m.group(1);
+            String month = m.group(2);
+            String day = m.group(3);
+            String hour = m.group(4);
+            String minute = m.group(5);
+            String second = m.group(6);
+            cal.clear();
+            cal.set(
+                Integer.parseInt(year),
+                calendarMonth(month),
+                Integer.parseInt(day),
+                Integer.parseInt(hour),
+                Integer.parseInt(minute),
+                Integer.parseInt(second)
+            );
+            return cal.getTime();
+        }
+
+        m = DD_MM_YYYYThh_mm.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String year = m.group(3);
+            String month = m.group(2);
+            String day = m.group(1);
+            String hour = m.group(4);
+            String minute = m.group(5);
+            cal.clear();
+            cal.set(
+                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
+                calendarMonth(month),
+                Integer.parseInt(day),
+                Integer.parseInt(hour),
+                Integer.parseInt(minute),
+                0
+            );
+            return cal.getTime();
+        }
+
+        m = DD_MM_YYYYThh_mm_ss.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String year = m.group(3);
+            String month = m.group(2);
+            String day = m.group(1);
+            String hour = m.group(4);
+            String minute = m.group(5);
+            String second = m.group(6);
+            cal.clear();
+            cal.set(
+                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
+                calendarMonth(month),
+                Integer.parseInt(day),
+                Integer.parseInt(hour),
+                Integer.parseInt(minute),
+                Integer.parseInt(second)
+            );
+            return cal.getTime();
+        }
+
+        m = DDMMYY.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String day   = m.group(1);
+            String month = m.group(2);
+            String yearS = m.group(3);
+            int year = Integer.parseInt(yearS);
+
+            if (year <= cal.get(Calendar.YEAR) % 100) {
+                year += 2000;
+            }
+            else {
+                year += 1900;
+            }
+            cal.clear();
+            cal.set(
+                year,
+                Integer.parseInt(month),  // month
+                Integer.parseInt(day), // day
+                12, 0, 0);
+            return cal.getTime();
+        }
+
+        m = GARBAGE_YYYY.matcher(s);
+
+        if (m.matches()) {
+            Calendar cal = Calendar.getInstance();
+            String year = m.group(1);
+            cal.clear();
+            cal.set(
+                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
+                5,  // month
+                15, // day
+                12, 0, 0);
+            return cal.getTime();
+        }
+
+        throw new IllegalArgumentException();
+    }
+
+    public static void main(String [] args) {
+        for (int i = 0; i < args.length; ++i) {
+            System.out.println(args[i] + ": " + guessDate(args[i]));
+        }
+    }
+}
+// end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend/src/main/java/org/dive4elements/river/backend/utils/DateUtil.java	Thu Sep 04 15:03:25 2014 +0200
@@ -0,0 +1,37 @@
+/* Copyright (C) 2014 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.backend.utils;
+
+import java.util.Date;
+import java.util.Calendar;
+
+public final class DateUtil {
+
+    private DateUtil() {
+    }
+
+    /** Create Date on first moment (1st jan) of given year. */
+    public static Date getStartDateFromYear(int year) {
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(year, 0, 1, 0, 0, 0);
+
+        return cal.getTime();
+    }
+
+
+    /** Create Date on last moment (31st dec) of given year. */
+    public static Date getEndDateFromYear(int year) {
+        Calendar cal = Calendar.getInstance();
+        cal.clear();
+        cal.set(year, 11, 31, 23, 59, 59);
+
+        return cal.getTime();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend/src/main/java/org/dive4elements/river/backend/utils/DouglasPeuker.java	Thu Sep 04 15:03:25 2014 +0200
@@ -0,0 +1,81 @@
+package org.dive4elements.river.backend.utils;
+
+import org.dive4elements.river.importer.XY; // TODO: Move to a more common package.
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public final class DouglasPeuker
+{
+    public static final double EPSILON = 1e-4;
+
+    private DouglasPeuker() {
+    }
+
+    public static List<XY> simplify(List<XY> input) {
+        return simplify(input, EPSILON);
+    }
+
+    public static List<XY> simplify(List<XY> input, double epsilon) {
+
+        int N = input.size();
+
+        if (N < 3) {
+            return new ArrayList<XY>(input);
+        }
+
+        List<XY> simplified = recursiveSimplify(input, 0, N-1, epsilon);
+
+        List<XY> output = new ArrayList<XY>(simplified.size()+2);
+        output.add(input.get(0));
+        output.addAll(simplified);
+        output.add(input.get(N-1));
+
+        return output;
+    }
+
+    private static List recursiveSimplify(
+        List<XY> input,
+        int      start,
+        int      end,
+        double   epsilon
+    ) {
+        XY a = input.get(start);
+        XY b = input.get(end);
+
+        // Normal of hesse normal form.
+        XY n = new XY(b).sub(a).ortho().normalize();
+
+        // distance offset of the hesse normal form.
+        double d = n.lineOffset(a);
+
+        double maxDist = -Double.MAX_VALUE;
+        int maxIdx = -1;
+
+        for (int i = start+1; i < end; ++i) {
+            double dist = Math.abs(n.dot(input.get(i)) + d);
+            if (dist > maxDist) {
+                maxDist = dist;
+                maxIdx  = i;
+            }
+        }
+
+        if (maxDist < epsilon) {
+            // All points between a and b can be ignored.
+            return Collections.<XY>emptyList();
+        }
+
+        // Split by input[maxIdx].
+        List<XY> before = recursiveSimplify(input, start, maxIdx, epsilon);
+        List<XY> after  = recursiveSimplify(input, maxIdx, end, epsilon);
+
+        List<XY> output = new ArrayList<XY>(before.size()+1+after.size());
+        output.addAll(before);
+        output.add(input.get(maxIdx));
+        output.addAll(after);
+
+        return output;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend/src/main/java/org/dive4elements/river/backend/utils/EpsilonComparator.java	Thu Sep 04 15:03:25 2014 +0200
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.backend.utils;
+
+import java.util.Comparator;
+import java.io.Serializable;
+
+/** Comparator with some tolerance (epsilon). */
+public class EpsilonComparator implements Comparator<Double>, Serializable
+{
+    public static final double EPSILON = 1e-4;
+
+    /** Ready-made comparator with 1e-4 tolerance. */
+    public static final EpsilonComparator CMP = new EpsilonComparator(EPSILON);
+
+    private double epsilon;
+
+    public EpsilonComparator(double epsilon) {
+        this.epsilon = epsilon;
+    }
+
+    @Override
+    public int compare(Double a, Double b) {
+        double diff = a - b;
+        if (diff < -epsilon) return -1;
+        if (diff >  epsilon) return +1;
+        return 0;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/backend/src/main/java/org/dive4elements/river/backend/utils/StringUtil.java	Thu Sep 04 15:03:25 2014 +0200
@@ -0,0 +1,828 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.backend.utils;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import java.net.URLEncoder;
+import java.net.URLDecoder;
+
+import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
+
+public final class StringUtil {
+    final static String NUMBER_SEPERATOR = ";";
+    final static String LINE_SEPERATOR = ":";
+
+    private StringUtil() {
+    }
+
+    public static final String double2DArrayToString(double[][] values) {
+
+        if (values == null) {
+            throw new IllegalArgumentException("keine double[][]-Werte");
+        }
+
+        StringBuilder strbuf = new StringBuilder();
+
+        for (int i=0; i < values.length; i++) {
+            if (i>0) {
+                strbuf.append(LINE_SEPERATOR);
+            }
+            for (int j=0; j < values[i].length; j++) {
+                if (j > 0) {
+                    strbuf.append(NUMBER_SEPERATOR);
+                }
+                strbuf.append(values[i][j]);
+            }
+        }
+
+        return strbuf.toString();
+    }
+
+    public static final double[][] stringToDouble2DArray(String str) {
+        if (str == null || str.length() == 0) {
+            return null;
+        }
+
+        String[] lineSplit = str.split(LINE_SEPERATOR);
+        double[][] array2D = new double[lineSplit.length][];
+        for (int i=0; i < lineSplit.length; i++) {
+            String[] numberSplit =  lineSplit[i].split(NUMBER_SEPERATOR);
+
+            double[] numbers = new double[numberSplit.length];
+            for (int j=0; j < numberSplit.length; j++) {
+                numbers[j] = Double.valueOf(numberSplit[j]).doubleValue();
+            }
+
+            array2D[i] = numbers;
+        }
+
+        return array2D;
+    }
+
+    /**
+     * Remove first occurrence of "[" and "]" (if both do occur).
+     * @param value String to be stripped of [] (might be null).
+     * @return input string but with [ and ] removed, or input string if no
+     *         brackets were found.
+     */
+    public static final String unbracket(String value) {
+        // null- guard
+        if (value == null) return value;
+
+        int start = value.indexOf("[");
+        int end   = value.indexOf("]");
+
+        if (start < 0 || end < 0) {
+            return value;
+        }
+
+        value = value.substring(start + 1, end);
+
+        return value;
+    }
+
+
+    /**
+     * From "Q=1" make "W(Q=1)".
+     * @return original string wraped in "W()" if it contains a "Q", original
+     *         string otherwise.
+     */
+    public static String wWrap(String wOrQ) {
+        return (wOrQ != null && wOrQ.indexOf("Q") >=0)
+               ? "W(" + wOrQ + ")"
+               : wOrQ;
+        }
+
+
+    public static final String [] splitLines(String s) {
+        if (s == null) {
+            return null;
+        }
+        ArrayList<String> list = new ArrayList<String>();
+
+        BufferedReader in = null;
+
+        try {
+            in =
+                new BufferedReader(
+                new StringReader(s));
+
+            String line;
+
+            while ((line = in.readLine()) != null) {
+                list.add(line);
+            }
+        }
+        catch (IOException ioe) {
+            return null;
+        }
+        finally {
+            if (in != null)
+                try {
+                    in.close();
+                }
+                catch (IOException ioe) {}
+        }
+
+        return list.toArray(new String[list.size()]);
+    }
+
+    public static final String concat(String [] s) {
+        return concat(s, null);
+    }
+
+    public static final String concat(String [] s, String glue) {
+        if (s == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < s.length; ++i) {
+            if (i > 0 && glue != null) {
+                sb.append(glue);
+            }
+            sb.append(s[i]);
+        }
+        return sb.toString();
+    }
+
+    public static final String [] splitAfter(String [] src, int N) {
+        if (src == null) {
+            return null;
+        }
+
+        ArrayList<String> list = new ArrayList<String>(src.length);
+        for (int i = 0; i < src.length; ++i) {
+            String s = src[i];
+            int R;
+            if (s == null || (R = s.length()) == 0) {
+                list.add(s);
+            }
+            else {
+                while (R > N) {
+                    list.add(s.substring(0, N));
+                    s = s.substring(N);
+                    R = s.length();
+                }
+                list.add(s);
+            }
+        }
+        return list.toArray(new String[list.size()]);
+    }
+
+    public static final String [] splitQuoted(String s) {
+        return splitQuoted(s, '"');
+    }
+
+    public static final String[] fitArray(String [] src, String [] dst) {
+        if (src == null) {
+            return dst;
+        }
+        if (dst == null) {
+            return src;
+        }
+
+        if (src.length == dst.length) {
+            return src;
+        }
+
+        System.arraycopy(src, 0, dst, 0, Math.min(dst.length, src.length));
+
+        return dst;
+    }
+
+    public static final String [] splitQuoted(String s, char quoteChar) {
+        if (s == null) {
+            return null;
+        }
+        ArrayList<String> l = new ArrayList<String>();
+        int mode = 0, last_mode = 0;
+        StringBuilder sb = new StringBuilder();
+        for (int N = s.length(), i = 0; i < N; ++i) {
+            char c = s.charAt(i);
+            switch (mode) {
+                case 0: // unquoted mode
+                    if (c == quoteChar) {
+                        mode = 1; // to quoted mode
+                        if (sb.length() > 0) {
+                            l.add(sb.toString());
+                            sb.setLength(0);
+                        }
+                    }
+                    else if (c == '\\') {
+                        last_mode = 0;
+                        mode = 2; // escape mode
+                    }
+                    else if (!Character.isWhitespace(c)) {
+                        sb.append(c);
+                    }
+                    else if (sb.length() > 0) {
+                        l.add(sb.toString());
+                        sb.setLength(0);
+                    }
+                    break;
+                case 1: // quote mode
+                    if (c == '\\') {
+                        last_mode = 1;
+                        mode = 2; // escape mode
+                    }
+                    else if (c == quoteChar) { // leave quote mode
+                        l.add(sb.toString());
+                        sb.setLength(0);
+                        mode = 0; // to unquoted mode
+                    }
+                    else {
+                        sb.append(c);
+                    }
+                    break;
+                case 2: // escape mode
+                    sb.append(c);
+                    mode = last_mode;
+                    break;
+            }
+        }
+        if (sb.length() > 0) {
+            l.add(sb.toString());
+        }
+        return l.toArray(new String[l.size()]);
+    }
+
+    public static final String [] splitUnique(String s) {
+        return splitUnique(s, "[\\s,]+");
+    }
+
+    public static final String [] splitUnique(String s, String sep) {
+        return s != null ? unique(s.split(sep)) : null;
+    }
+
+    public static final String [] unique(String [] str) {
+        if (str == null || str.length == 1) {
+            return str;
+        }
+
+        Arrays.sort(str);
+
+        for (int i = 1; i < str.length; ++i)
+            if (str[i].equals(str[i-1])) {
+                ArrayList<String> list = new ArrayList<String>(str.length);
+
+                for (int j = 0; j < i; ++j) {
+                    list.add(str[j]);
+                }
+
+                String last = str[i];
+
+                for (++i; i < str.length; ++i)
+                    if (!last.equals(str[i])) {
+                        list.add(last = str[i]);
+                    }
+
+                return list.toArray(new String[list.size()]);
+            }
+
+        return str;
+    }
+
+    public static final String [] ensureEmptyExistence(String [] str) {
+        if (str == null) {
+            return null;
+        }
+
+        for (int i = 0; i < str.length; ++i)
+            if (str[i].length() == 0) {
+                if (i != 0) { // copy to front
+                    String t = str[0];
+                    str[0] = str[i];
+                    str[i] = t;
+                }
+                return str;
+            }
+
+        String [] n = new String[str.length+1];
+        n[0] = "";
+        System.arraycopy(str, 0, n, 1, str.length);
+        return n;
+    }
+
+    public static final String ensureWidthPadLeft(String s, int width, char pad) {
+        int N = s.length();
+        if (N >= width) {
+            return s;
+        }
+        StringBuilder sb = new StringBuilder(width);
+        for (; N < width; ++N) {
+            sb.append(pad);
+        }
+        sb.append(s);
+        return sb.toString();
+    }
+
+    public static final String [] splitWhiteSpaceWithNAsPad(
+        String s,
+        int    N,
+        String pad
+    ) {
+        if (s == null) {
+            return null;
+        }
+
+        boolean copyChars = true;
+        int     count     = 0; // number of WS
+
+        int S = s.length();
+
+        ArrayList<String> parts = new ArrayList<String>();
+
+        StringBuilder part = new StringBuilder(S);
+
+        for (int i = 0; i < S; ++i) {
+            char c = s.charAt(i);
+            if (copyChars) { // char mode
+                if (Character.isWhitespace(c)) {
+                    if (part.length() > 0) {
+                        parts.add(part.toString());
+                        part.setLength(0);
+                    }
+                    count     = 1;
+                    copyChars = false; // to WS mode
+                }
+                else {
+                    part.append(c);
+                }
+            }
+            else { // counting WS
+                if (Character.isWhitespace(c)) {
+                    ++count;
+                }
+                else {
+                    while (count >= N) {// enough to insert pad?
+                        parts.add(pad);
+                        count -= N;
+                    }
+                    part.append(c);
+                    count     = 0;
+                    copyChars = true; // back to char mode
+                }
+            }
+        } // for all chars
+
+        if (copyChars) {
+            if (part.length() > 0) {
+                parts.add(part.toString());
+            }
+        }
+        else {
+            while (count >= N) { // enough to insert pad?
+                parts.add(pad);
+                count -= N;
+            }
+        }
+
+        return parts.toArray(new String[parts.size()]);
+    }
+
+    public static final String encodeURL(String url) {
+        try {
+            return url != null
+                   ? URLEncoder.encode(url, "UTF-8")
+                   : "";
+        }
+        catch (UnsupportedEncodingException usee) {
+            throw new RuntimeException(usee.getLocalizedMessage());
+        }
+    }
+
+    public static final String decodeURL(String url) {
+        try {
+            return url != null
+                   ? URLDecoder.decode(url, "UTF-8")
+                   : "";
+        }
+        catch (UnsupportedEncodingException usee) {
+            throw new RuntimeException(usee.getLocalizedMessage());
+        }
+    }
+
+    public static final boolean isEmpty(String s) {
+        return s == null || s.length() == 0;
+    }
+
+    public static final String empty(String s) {
+        return s == null ? "" : s;
+    }
+
+
+    public static final String trim(String s) {
+        return s != null ? s.trim() : null;
+    }
+
+    public static final String uniqueWhitespaces(String s) {
+        if (s == null) {
+            return null;
+        }
+
+        boolean wasWS = false;
+        StringBuilder sb = new StringBuilder();
+
+        for (int N = s.length(), i = 0; i < N; ++i) {
+            char c = s.charAt(i);
+            if (Character.isWhitespace(c)) {
+                if (!wasWS) {
+                    sb.append(c);
+                    wasWS = true;
+                }
+            }
+            else {
+                sb.append(c);
+                wasWS = false;
+            }
+        }
+
+        return sb.toString();
+    }
+
+    public static final String replaceNewlines(String s) {
+        return s == null
+               ? null
+               : s.replace('\r', ' ').replace('\n', ' ');
+    }
+
+    /*
+    public static final String quoteReplacement(String s) {
+
+        if (s == null || (s.indexOf('\\') == -1 && s.indexOf('$') == -1))
+            return s;
+
+        StringBuilder sb = new StringBuilder();
+
+        for (int N = s.length(), i = 0; i < N; ++i) {
+            char c = s.charAt(i);
+            if (c == '\\' || c == '$') sb.append('\\');
+            sb.append(c);
+        }
+
+        return sb.toString();
+    }
+    */
+
+    public static final String quoteReplacement(String s) {
+
+        if (s == null) {
+            return null;
+        }
+
+        for (int N = s.length(), i = 0; i < N; ++i) { // plain check loop
+            char c = s.charAt(i);
+            if (c == '$' || c == '\\') { // first special -> StringBuilder
+                StringBuilder sb = new StringBuilder(s.substring(0, i))
+                .append('\\')
+                .append(c);
+                for (++i; i < N; ++i) { // build StringBuilder with rest
+                    if ((c = s.charAt(i)) == '$' || c == '\\') {
+                        sb.append('\\');
+                    }
+                    sb.append(c);
+                }
+                return sb.toString();
+            }
+        }
+
+        return s;
+    }
+
+    public static final String repeat(String what, int times) {
+        return repeat(what, times, new StringBuilder()).toString();
+    }
+
+    public static final StringBuilder repeat(String what, int times, StringBuilder sb) {
+        while (times-- > 0) {
+            sb.append(what);
+        }
+        return sb;
+    }
+
+    /**
+     * Returns the file name without extension.
+     */
+    public static final String cutExtension(String s) {
+        if (s == null) {
+            return null;
+        }
+        int dot = s.lastIndexOf('.');
+        return dot >= 0
+               ? s.substring(0, dot)
+               : s;
+    }
+
+    public static final String extension(String s) {
+        if (s == null) {
+            return null;
+        }
+        int dot = s.lastIndexOf('.');
+        return dot >= 0
+               ? s.substring(dot+1)
+               : s;
+    }
+
+    public static final String [] splitExtension(String x) {
+        if (x == null) {
+            return null;
+        }
+        int i = x.lastIndexOf('.');
+        return i < 0
+               ? new String[] { x, null }
+               : new String[] { x.substring(0, Math.max(0, i)), x.substring(i+1).toLowerCase() };
+    }
+
+    public static String entityEncode(String s) {
+        if (s == null || s.length() == 0) {
+            return s;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (int i=0, N =s.length(); i < N; i++) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '<':
+                    sb.append("&lt;");
+                    break;
+                case '>':
+                    sb.append("&gt;");
+                    break;
+                case '&':
+                    sb.append("&amp;");
+                    break;
+                default:
+                    sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String entityDecode(String s) {
+        if (s == null || s.length() == 0) {
+            return s;
+        }
+
+        boolean amp = false;
+        StringBuilder sb = new StringBuilder();
+        StringBuilder ampbuf = new StringBuilder();
+        for (int i=0, N =s.length(); i < N; i++) {
+            char c = s.charAt(i);
+            if (amp) {
+                if (c == ';') {
+                    amp = false;
+                    String str = ampbuf.toString();
+                    ampbuf.setLength(0);
+                    if (str.equals("lt")) {
+                        sb.append('<');
+                    }
+                    else if (str.equals("gt")) {
+                        sb.append('>');
+                    }
+                    else if (str.equals("amp")) {
+                        sb.append('&');
+                    }
+                    else {
+                        sb.append('&').append(str).append(';');
+                    }
+                }
+                else {
+                    ampbuf.append(c);
+                }
+            }
+            else if (c=='&') {
+                amp = true;
+            }
+            else {
+                sb.append(c);
+            }
+
+        }
+        return sb.toString();
+    }
+
+    public static final String quote(String s) {
+        return quote(s, '"');
+    }
+
+    public static final String quote(String s, char quoteChar) {
+        if (s == null) {
+            return null;
+        }
+
+        int N = s.length();
+
+        if (N == 0)
+            return new StringBuilder(2)
+                   .append(quoteChar)
+                   .append(quoteChar)
+                   .toString();
+
+        StringBuilder sb = null;
+
+        int i = 0;
+
+        for (; i < N; ++i) {
+            char c = s.charAt(i);
+
+            if (Character.isWhitespace(c)) {
+                sb = new StringBuilder()
+                .append(quoteChar)
+                .append(s.substring(0, i+1));
+                break;
+            }
+            else if (c == quoteChar) {
+                sb = new StringBuilder()
+                .append(quoteChar)
+                .append(s.substring(0, i))
+                .append('\\')
+                .append(quoteChar);
+                break;
+            }
+        }
+
+        if (sb == null) {
+            return s;
+        }
+
+        for (++i; i < N; ++i) {
+            char c = s.charAt(i);
+            if (c == quoteChar || c == '\\') {
+                sb.append('\\');
+            }
+
+            sb.append(c);
+        }
+
+        return sb.append(quoteChar).toString();
+    }
+
+    /*
+    public static String sprintf(String format, Object... args) {
+        return sprintf(null, format, args);
+    }
+    */
+
+    public static String sprintf(Locale locale, String format, Object ... args) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.printf(locale, format, args);
+        pw.flush();
+        return sw.toString();
+    }
+
+
+    public static void testQuote() {
+        System.err.println("testing quote:");
+
+        String cases []  = {
+            "",          "''",
+            "test",      "test",
+            "test test", "'test test'",
+            "  test",    "'  test'",
+            "test   ",   "'test   '",
+            " test ",    "' test '",
+            "'test",     "'\\'test'",
+            "'",         "'\\''",
+            " ' ' ",     "' \\' \\' '",
+            "te'st",     "'te\\'st'"
+        };
+
+        int failed = 0;
+
+        for (int i = 0; i < cases.length; i += 2) {
+            String in  = cases[i];
+            String out = cases[i+1];
+
+            String res = quote(in, '\'');
+            if (!res.equals(out)) {
+                ++failed;
+                System.err.println(
+                    "quote failed on: >" + in +
+                    "< result: >" + res +
+                    "< expected: >" + out + "<");
+            }
+        }
+
+        int T = cases.length/2;
+
+        System.err.println("tests total: "  + T);
+        System.err.println("tests failed: " + failed);
+        System.err.println("tests passed: " + (T - failed));
+    }
+
+    public static void testQuoteReplacement() {
+        System.err.println("testing quoteReplacement:");
+
+        String cases []  = {
+            "",          "",
+            "test",      "test",
+            "$",         "\\$",
+            "\\",        "\\\\",
+            "\\$",       "\\\\\\$",
+            "test\\$",   "test\\\\\\$",
+            "\\test",    "\\\\test",
+            "test$",     "test\\$",
+            "test$test", "test\\$test",
+            "$test$",    "\\$test\\$"
+        };
+
+        int failed = 0;
+
+        for (int i = 0; i < cases.length; i += 2) {
+            String in  = cases[i];
+            String out = cases[i+1];
+
+            String res = quoteReplacement(in);
+            if (!res.equals(out)) {
+                ++failed;
+                System.err.println(
+                    "quoteReplacement failed on: '" + in +
+                    "' result: '" + res +
+                    "' expected: '" + out + "'");
+            }
+        }
+
+        int T = cases.length/2;
+
+        System.err.println("tests total: "  + T);
+        System.err.println("tests failed: " + failed);
+        System.err.println("tests passed: " + (T - failed));
+    }
+
+    public static void testStringArray2D() {
+        int total = 0;
+        int fail = 0;
+        int passed = 0;
+
+        System.err.println("testing StringArray2D:");
+
+        double[][] testarray = {{1.0, 2.0, 3.0},
+            {1.1, 2.1, 3.1},
+            {100.2, 200.2}
+        };
+        String str = double2DArrayToString(testarray);
+
+        total += 1;
+        if (str.equals("1.0;2.0;3.0:1.1;2.1;3.1:100.2;200.2")) {
+            passed +=1;
+        }
+        else {
+            fail +=1;
+            System.err.println("Der Ergebnis-String ist nicht richtig:");
+            System.err.println(str);
+        }
+
+
+
+        double[][] testarray2 = stringToDouble2DArray(str);
+        boolean failed = false;
+
+        total +=1;
+        for (int i=0; i < testarray.length; i++)
+            for (int j=0; j < testarray[i].length; j++)
+                if (testarray[i][j] != testarray2[i][j]) {
+                    System.err.println("Test scheitert bei i=" +i +" j=" +j);
+                    System.err.println("alter Wert=" + testarray[i][j] +" neuer Wert=" +testarray2[i][j]);
+                    failed = true;
+                }
+        if (failed) {
+            fail +=1;
+        }
+        else {
+            passed +=1;
+        }
+        System.err.println("tests total: "+ total);
+        System.err.println("tests failed: "+ fail);
+        System.err.println("tests passed: "+ passed);
+    }
+
+    public static void main(String [] args) {
+
+        testQuoteReplacement();
+        testQuote();
+        testStringArray2D();
+    }
+
+    /** Check for occurence of needle in hay, converting both to lowercase
+     * to be ignorant of cases. */
+    public static boolean containsIgnoreCase(String hay, String needle) {
+        return hay.toLowerCase().contains(needle.toLowerCase());
+    }
+}
+// end of file
--- a/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java	Thu Sep 04 15:03:25 2014 +0200
@@ -41,7 +41,7 @@
 import org.dive4elements.river.model.River;
 import org.dive4elements.river.model.Unit;
 
-import org.dive4elements.river.utils.DouglasPeuker;
+import org.dive4elements.river.backend.utils.DouglasPeuker;
 
 import java.io.File;
 import java.io.IOException;
--- a/backend/src/main/java/org/dive4elements/river/importer/Importer.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/Importer.java	Thu Sep 04 15:03:25 2014 +0200
@@ -30,7 +30,7 @@
 
 import org.w3c.dom.Document;
 
-import org.dive4elements.river.utils.StringUtil;
+import org.dive4elements.river.backend.utils.StringUtil;
 
 /** Data Importer. Further processing happens per-river. */
 public class Importer
--- a/backend/src/main/java/org/dive4elements/river/importer/ImporterSession.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImporterSession.java	Thu Sep 04 15:03:25 2014 +0200
@@ -28,7 +28,7 @@
 import org.dive4elements.river.model.DischargeTable;
 import org.dive4elements.river.model.Range;
 import org.dive4elements.river.model.River;
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 import org.dive4elements.artifacts.common.utils.LRUCache;
 
 public class ImporterSession
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/AbstractSedimentLoadParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/AbstractSedimentLoadParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -25,8 +25,8 @@
 
 import org.dive4elements.river.model.GrainFraction;
 
-import org.dive4elements.river.utils.DateUtil;
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.DateUtil;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 
 /** Parses sediment load files. */
 public abstract class AbstractSedimentLoadParser extends LineParser {
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/BedHeightParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/BedHeightParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -40,8 +40,8 @@
 import org.dive4elements.river.importer.ImportUnit;
 import org.dive4elements.river.model.BedHeightType;
 import org.dive4elements.river.importer.ImporterSession;
-import org.dive4elements.river.utils.EpsilonComparator;
-import org.dive4elements.river.utils.DateUtil;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.DateUtil;
 
 public abstract class BedHeightParser {
 
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/DA50Parser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/DA50Parser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -22,11 +22,11 @@
 
 import org.dive4elements.artifacts.common.utils.FileTools;
 
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 
 
 /**
- * To create cross-sections, generate: Map<double,list<xy>> from files
+ * To create cross-sections, generate: Map[double,list[xy]] from files
  * in da50 format.
  */
 public class DA50Parser extends LineParser implements CrossSectionParser
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/DA66Parser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/DA66Parser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -12,7 +12,7 @@
 
 import org.dive4elements.river.importer.XY;
 
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 
 import java.io.File;
 import java.io.IOException;
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/FlowVelocityModelParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/FlowVelocityModelParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -25,7 +25,7 @@
 import org.dive4elements.river.importer.ImportDischargeZone;
 import org.dive4elements.river.importer.ImportFlowVelocityModel;
 import org.dive4elements.river.importer.ImportFlowVelocityModelValue;
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 
 
 public class FlowVelocityModelParser extends LineParser {
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/NameAndTimeInterval.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/NameAndTimeInterval.java	Thu Sep 04 15:03:25 2014 +0200
@@ -14,7 +14,7 @@
 
 import org.apache.log4j.Logger;
 import org.dive4elements.river.importer.ImportTimeInterval;
-import org.dive4elements.river.utils.DateGuesser;
+import org.dive4elements.river.backend.utils.DateGuesser;
 
 public class NameAndTimeInterval {
 
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/PorosityParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/PorosityParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -12,7 +12,7 @@
 import org.dive4elements.river.importer.ImportPorosity;
 import org.dive4elements.river.importer.ImportPorosityValue;
 import org.dive4elements.river.importer.ImportTimeInterval;
-import org.dive4elements.river.utils.DateUtil;
+import org.dive4elements.river.backend.utils.DateUtil;
 
 import java.io.File;
 import java.io.IOException;
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/SQRelationParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/SQRelationParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -22,7 +22,7 @@
 import org.dive4elements.river.importer.ImportSQRelation;
 import org.dive4elements.river.importer.ImportSQRelationValue;
 import org.dive4elements.river.importer.ImportTimeInterval;
-import org.dive4elements.river.utils.DateUtil;
+import org.dive4elements.river.backend.utils.DateUtil;
 
 
 public class SQRelationParser extends LineParser {
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/W80CSVParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/W80CSVParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -14,8 +14,8 @@
 
 import org.dive4elements.river.importer.parsers.tim.Coordinate;
 
-import org.dive4elements.river.utils.DateGuesser;
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.DateGuesser;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 
 import java.io.File;
 import java.io.IOException;
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/W80Parser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/W80Parser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -14,8 +14,8 @@
 
 import org.dive4elements.river.importer.parsers.tim.Coordinate;
 
-import org.dive4elements.river.utils.DateGuesser;
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.DateGuesser;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 
 import java.io.File;
 import java.io.IOException;
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/WaterlevelDifferencesParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/WaterlevelDifferencesParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -27,7 +27,7 @@
 import org.dive4elements.river.importer.ImportWstQRange;
 import org.dive4elements.river.importer.ImportWstColumn;
 import org.dive4elements.river.importer.ImportWstColumnValue;
-import org.dive4elements.river.utils.DateUtil;
+import org.dive4elements.river.backend.utils.DateUtil;
 
 
 /**
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/WaterlevelParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/WaterlevelParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -28,7 +28,7 @@
 import org.dive4elements.river.importer.ImportWstColumn;
 import org.dive4elements.river.importer.ImportWstColumnValue;
 import org.dive4elements.river.importer.ImportWstQRange;
-import org.dive4elements.river.utils.DateUtil;
+import org.dive4elements.river.backend.utils.DateUtil;
 
 
 /**
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/WstParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/WstParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -22,8 +22,8 @@
 
 import org.apache.log4j.Logger;
 
-import org.dive4elements.river.utils.StringUtil;
-import org.dive4elements.river.utils.DateGuesser;
+import org.dive4elements.river.backend.utils.StringUtil;
+import org.dive4elements.river.backend.utils.DateGuesser;
 
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/tim/TIMParser.java	Thu Sep 04 13:00:55 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/tim/TIMParser.java	Thu Sep 04 15:03:25 2014 +0200
@@ -21,7 +21,7 @@
 
 import org.apache.log4j.Logger;
 
-import org.dive4elements.river.utils.EpsilonComparator;
+import org.dive4elements.river.backend.utils.EpsilonComparator;
 
 /** Parser for single .tim files. */
 public class TIMParser
--- a/backend/src/main/java/org/dive4elements/river/utils/DBCPConnectionProvider.java	Thu Sep 04 13:00:55 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,261 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-/*
- * Copyright 2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.dive4elements.river.utils;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-
-import java.util.Iterator;
-import java.util.Properties;
-import java.util.Map;
-import java.util.Collections;
-import java.util.StringTokenizer;
-
-import org.apache.commons.dbcp.BasicDataSource;
-import org.apache.commons.dbcp.BasicDataSourceFactory;
-
-import org.apache.log4j.Logger;
-
-import org.hibernate.HibernateException;
-
-import org.hibernate.connection.ConnectionProviderFactory;
-import org.hibernate.connection.ConnectionProvider;
-
-import org.hibernate.cfg.Environment;
-
-/**
- * <p>A connection provider that uses an Apache commons DBCP connection pool.</p>
- *
- * <p>To use this connection provider set:<br>
- * <code>hibernate.connection.provider_class&nbsp;org.hibernate.connection.DBCPConnectionProvider</code></p>
- *
- * <pre>Supported Hibernate properties:
- *   hibernate.connection.driver_class
- *   hibernate.connection.url
- *   hibernate.connection.username
- *   hibernate.connection.password
- *   hibernate.connection.isolation
- *   hibernate.connection.autocommit
- *   hibernate.connection.pool_size
- *   hibernate.connection (JDBC driver properties)</pre>
- * <br>
- * All DBCP properties are also supported by using the hibernate.dbcp prefix.
- * A complete list can be found on the DBCP configuration page:
- * <a href="http://jakarta.apache.org/commons/dbcp/configuration.html">http://jakarta.apache.org/commons/dbcp/configuration.html</a>.
- * <br>
- * <pre>Example:
- *   hibernate.connection.provider_class org.hibernate.connection.DBCPConnectionProvider
- *   hibernate.connection.driver_class org.hsqldb.jdbcDriver
- *   hibernate.connection.username sa
- *   hibernate.connection.password
- *   hibernate.connection.url jdbc:hsqldb:test
- *   hibernate.connection.pool_size 20
- *   hibernate.dbcp.initialSize 10
- *   hibernate.dbcp.maxWait 3000
- *   hibernate.dbcp.validationQuery select 1 from dual</pre>
- *
- * <p>More information about configuring/using DBCP can be found on the
- * <a href="http://jakarta.apache.org/commons/dbcp/">DBCP website</a>.
- * There you will also find the DBCP wiki, mailing lists, issue tracking
- * and other support facilities</p>
- *
- * @see org.hibernate.connection.ConnectionProvider
- * @author Dirk Verbeeck
- */
-public class DBCPConnectionProvider
-implements   ConnectionProvider
-{
-    private static Logger log = Logger.getLogger(DBCPConnectionProvider.class);
-
-    private static final String PREFIX = "hibernate.dbcp.";
-
-    private BasicDataSource ds;
-
-    // Old Environment property for backward-compatibility
-    // (property removed in Hibernate3)
-    private static final String DBCP_PS_MAXACTIVE =
-        "hibernate.dbcp.ps.maxActive";
-
-    // Property doesn't exists in Hibernate2
-    private static final String AUTOCOMMIT =
-        "hibernate.connection.autocommit";
-
-    public void configure(Properties props) throws HibernateException {
-        try {
-            log.debug("Configure DBCPConnectionProvider");
-
-            // DBCP properties used to create the BasicDataSource
-            Properties dbcpProperties = new Properties();
-
-            // DriverClass & url
-            String jdbcDriverClass = props.getProperty(Environment.DRIVER);
-            String jdbcUrl = props.getProperty(Environment.URL);
-            dbcpProperties.put("driverClassName", jdbcDriverClass);
-            dbcpProperties.put("url", jdbcUrl);
-
-            // Username / password
-            String username = props.getProperty(Environment.USER);
-            String password = props.getProperty(Environment.PASS);
-            dbcpProperties.put("username", username);
-            dbcpProperties.put("password", password);
-
-            // Isolation level
-            String isolationLevel = props.getProperty(Environment.ISOLATION);
-            if (isolationLevel != null
-            && (isolationLevel = isolationLevel.trim()).length() > 0) {
-                dbcpProperties.put("defaultTransactionIsolation", isolationLevel);
-            }
-
-            // Turn off autocommit (unless autocommit property is set)
-            String autocommit = props.getProperty(AUTOCOMMIT);
-            if (autocommit != null
-            && (autocommit = autocommit.trim()).length() > 0) {
-                dbcpProperties.put("defaultAutoCommit", autocommit);
-            } else {
-                dbcpProperties.put("defaultAutoCommit", String.valueOf(Boolean.FALSE));
-            }
-
-            // Pool size
-            String poolSize = props.getProperty(Environment.POOL_SIZE);
-            if (poolSize != null
-            && (poolSize = poolSize.trim()).length() > 0
-            && Integer.parseInt(poolSize) > 0)  {
-                dbcpProperties.put("maxActive", poolSize);
-            }
-
-            // Copy all "driver" properties into "connectionProperties"
-            Properties driverProps =
-                ConnectionProviderFactory.getConnectionProperties(props);
-
-            if (driverProps.size() > 0) {
-                StringBuilder connectionProperties = new StringBuilder();
-                for (Iterator iter = driverProps.entrySet().iterator();
-                    iter.hasNext();
-                ) {
-                    Map.Entry entry = (Map.Entry)iter.next();
-                    String    key   = (String)entry.getKey();
-                    String    value = (String)entry.getValue();
-                    connectionProperties
-                        .append(key)
-                        .append('=')
-                        .append(value);
-                    if (iter.hasNext()) {
-                        connectionProperties.append(';');
-                    }
-                }
-                dbcpProperties.put(
-                    "connectionProperties", connectionProperties.toString());
-            }
-
-            // Copy all DBCP properties removing the prefix
-            for (Iterator iter = props.entrySet().iterator() ; iter.hasNext() ;) {
-                Map.Entry entry = (Map.Entry)iter.next();
-                String    key   = (String)entry.getKey();
-                if (key.startsWith(PREFIX)) {
-                    String property = key.substring(PREFIX.length());
-                    String value    = (String)entry.getValue();
-                    dbcpProperties.put(property, value);
-                }
-            }
-
-            // Backward-compatibility
-            if (props.getProperty(DBCP_PS_MAXACTIVE) != null) {
-                dbcpProperties.put(
-                    "poolPreparedStatements",
-                    String.valueOf(Boolean.TRUE));
-                dbcpProperties.put(
-                    "maxOpenPreparedStatements",
-                    props.getProperty(DBCP_PS_MAXACTIVE));
-            }
-
-            // Some debug info
-            /* // commented out, because it leaks the password
-            if (log.isDebugEnabled()) {
-                log.debug("Creating a DBCP BasicDataSource" +
-                          " with the following DBCP factory properties:");
-                StringWriter sw = new StringWriter();
-                dbcpProperties.list(new PrintWriter(sw, true));
-                log.debug(sw.toString());
-            }
-            */
-
-            // Let the factory create the pool
-            ds = (BasicDataSource)BasicDataSourceFactory
-                .createDataSource(dbcpProperties);
-
-            // This needs to be done manually as it is somehow ignored
-            // by the BasicDataSourceFactory if you set it as a dbcpProperty
-            String connectionInitSqls = props.getProperty("connectionInitSqls");
-            if (connectionInitSqls != null) {
-                StringTokenizer tokenizer = new StringTokenizer(connectionInitSqls, ";");
-                ds.setConnectionInitSqls(Collections.list(tokenizer));
-            }
-            // The BasicDataSource has lazy initialization
-            // borrowing a connection will start the DataSource
-            // and make sure it is configured correctly.
-
-            // Connection conn = ds.getConnection();
-            // conn.close();
-        }
-        catch (Exception e) {
-            String message = "Could not create a DBCP pool";
-            log.fatal(message, e);
-            if (ds != null) {
-                BasicDataSource x = ds; ds = null;
-                try {
-                    x.close();
-                }
-                catch (SQLException sqle) {
-                }
-            }
-            throw new HibernateException(message, e);
-        }
-        log.debug("Configure DBCPConnectionProvider complete");
-    }
-
-    public Connection getConnection() throws SQLException {
-        return ds.getConnection();
-    }
-
-    public void closeConnection(Connection conn) throws SQLException {
-        conn.close();
-    }
-
-    public void close() throws HibernateException {
-        try {
-            if (ds != null) {
-                BasicDataSource x = ds; ds = null;
-                x.close();
-            }
-        }
-        catch (SQLException sqle) {
-            throw new HibernateException("Could not close DBCP pool", sqle);
-        }
-    }
-
-    public boolean supportsAggressiveRelease() {
-        return false;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/backend/src/main/java/org/dive4elements/river/utils/DateGuesser.java	Thu Sep 04 13:00:55 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.utils;
-
-import java.util.Date;
-import java.util.Calendar;
-
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-
-public final class DateGuesser {
-    public static final String [] MONTH = {
-        "jan", "feb", "mrz", "apr", "mai", "jun",
-        "jul", "aug", "sep", "okt", "nov", "dez"
-    };
-
-    public static final int guessMonth(String s) {
-        s = s.toLowerCase();
-        for (int i = 0; i < MONTH.length; ++i)
-            if (MONTH[i].equals(s)) {
-                return i;
-            }
-        return -1;
-    }
-
-    public static final Pattern YYYY_MM_DD =
-        Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})$");
-
-    public static final Pattern DD_MM_YYYY =
-        Pattern.compile("^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{2,4})$");
-
-    public static final Pattern MMM_YYYY =
-        Pattern.compile("^(\\d{0,2})\\.?(\\w{3})\\.?(\\d{2,4})$");
-
-    public static final Pattern GARBAGE_YYYY =
-        Pattern.compile("^\\D*(\\d{2,4})$");
-
-    public static final Pattern YYYY_MM_DDThh_mm =
-        Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2})$");
-
-    public static final Pattern YYYY_MM_DDThh_mm_ss =
-        Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})$");
-
-    public static final Pattern DD_MM_YYYYThh_mm =
-        Pattern.compile("^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{2,4})T(\\d{1,2}):(\\d{2})$");
-
-    public static final Pattern DD_MM_YYYYThh_mm_ss =
-        Pattern.compile("^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{2,4})T(\\d{1,2}):(\\d{2}):(\\d{2})$");
-
-    public static final Pattern DDMMYY =
-        Pattern.compile("^(\\d{2})(\\d{2})(\\d{2})$");
-
-    private DateGuesser() {
-    }
-
-    public static final int calendarMonth(String month) {
-        return calendarMonth(Integer.parseInt(month));
-    }
-
-    public static final int calendarMonth(int month) {
-        return Math.max(Math.min(month-1, 11), 0);
-    }
-
-    /**
-     * Guess date by trying all different patterns.
-     * Throws IllegalArgumentException if not able to guess.
-     * @param s The date to be guessed (e.g. 11.02.2001).
-     * @return the parsed Date.
-     */
-    public static Date guessDate(String s) {
-        if (s == null || (s = s.trim()).length() == 0) {
-            throw new IllegalArgumentException();
-        }
-
-        Matcher m;
-
-        m = YYYY_MM_DD.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String year  = m.group(1);
-            String month = m.group(2);
-            String day   = m.group(3);
-            cal.clear();
-            cal.set(
-                Integer.parseInt(year),
-                calendarMonth(month),
-                Integer.parseInt(day),
-                12, 0, 0);
-            return cal.getTime();
-        }
-
-        m = DD_MM_YYYY.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String year  = m.group(3);
-            String month = m.group(2);
-            String day   = m.group(1);
-            cal.clear();
-            cal.set(
-                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
-                calendarMonth(month),
-                Integer.parseInt(day),
-                12, 0, 0);
-            return cal.getTime();
-        }
-
-        m = MMM_YYYY.matcher(s);
-
-        if (m.matches()) {
-            int month = guessMonth(m.group(2));
-            if (month >= 0) {
-                Calendar cal = Calendar.getInstance();
-                String year = m.group(3);
-                String day  = m.group(1);
-                cal.clear();
-                cal.set(
-                    Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
-                    month,
-                    day.length() == 0 ? 15 : Integer.parseInt(day),
-                    12, 0, 0);
-                return cal.getTime();
-            }
-        }
-
-        m = YYYY_MM_DDThh_mm.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String year = m.group(1);
-            String month = m.group(2);
-            String day = m.group(3);
-            String hour = m.group(4);
-            String minute = m.group(5);
-            cal.clear();
-            cal.set(
-                Integer.parseInt(year),
-                calendarMonth(month),
-                Integer.parseInt(day),
-                Integer.parseInt(hour),
-                Integer.parseInt(minute),
-                0
-            );
-            return cal.getTime();
-        }
-
-        m = YYYY_MM_DDThh_mm_ss.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String year = m.group(1);
-            String month = m.group(2);
-            String day = m.group(3);
-            String hour = m.group(4);
-            String minute = m.group(5);
-            String second = m.group(6);
-            cal.clear();
-            cal.set(
-                Integer.parseInt(year),
-                calendarMonth(month),
-                Integer.parseInt(day),
-                Integer.parseInt(hour),
-                Integer.parseInt(minute),
-                Integer.parseInt(second)
-            );
-            return cal.getTime();
-        }
-
-        m = DD_MM_YYYYThh_mm.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String year = m.group(3);
-            String month = m.group(2);
-            String day = m.group(1);
-            String hour = m.group(4);
-            String minute = m.group(5);
-            cal.clear();
-            cal.set(
-                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
-                calendarMonth(month),
-                Integer.parseInt(day),
-                Integer.parseInt(hour),
-                Integer.parseInt(minute),
-                0
-            );
-            return cal.getTime();
-        }
-
-        m = DD_MM_YYYYThh_mm_ss.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String year = m.group(3);
-            String month = m.group(2);
-            String day = m.group(1);
-            String hour = m.group(4);
-            String minute = m.group(5);
-            String second = m.group(6);
-            cal.clear();
-            cal.set(
-                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
-                calendarMonth(month),
-                Integer.parseInt(day),
-                Integer.parseInt(hour),
-                Integer.parseInt(minute),
-                Integer.parseInt(second)
-            );
-            return cal.getTime();
-        }
-
-        m = DDMMYY.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String day   = m.group(1);
-            String month = m.group(2);
-            String yearS = m.group(3);
-            int year = Integer.parseInt(yearS);
-
-            if (year <= cal.get(Calendar.YEAR) % 100) {
-                year += 2000;
-            }
-            else {
-                year += 1900;
-            }
-            cal.clear();
-            cal.set(
-                year,
-                Integer.parseInt(month),  // month
-                Integer.parseInt(day), // day
-                12, 0, 0);
-            return cal.getTime();
-        }
-
-        m = GARBAGE_YYYY.matcher(s);
-
-        if (m.matches()) {
-            Calendar cal = Calendar.getInstance();
-            String year = m.group(1);
-            cal.clear();
-            cal.set(
-                Integer.parseInt(year) + (year.length() == 2 ? 1900 : 0),
-                5,  // month
-                15, // day
-                12, 0, 0);
-            return cal.getTime();
-        }
-
-        throw new IllegalArgumentException();
-    }
-
-    public static void main(String [] args) {
-        for (int i = 0; i < args.length; ++i) {
-            System.out.println(args[i] + ": " + guessDate(args[i]));
-        }
-    }
-}
-// end of file
--- a/backend/src/main/java/org/dive4elements/river/utils/DateUtil.java	Thu Sep 04 13:00:55 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/* Copyright (C) 2014 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.utils;
-
-import java.util.Date;
-import java.util.Calendar;
-
-public final class DateUtil {
-
-    private DateUtil() {
-    }
-
-    /** Create Date on first moment (1st jan) of given year. */
-    public static Date getStartDateFromYear(int year) {
-        Calendar cal = Calendar.getInstance();
-        cal.clear();
-        cal.set(year, 0, 1, 0, 0, 0);
-
-        return cal.getTime();
-    }
-
-
-    /** Create Date on last moment (31st dec) of given year. */
-    public static Date getEndDateFromYear(int year) {
-        Calendar cal = Calendar.getInstance();
-        cal.clear();
-        cal.set(year, 11, 31, 23, 59, 59);
-
-        return cal.getTime();
-    }
-}
--- a/backend/src/main/java/org/dive4elements/river/utils/DouglasPeuker.java	Thu Sep 04 13:00:55 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-package org.dive4elements.river.utils;
-
-import org.dive4elements.river.importer.XY; // TODO: Move to a more common package.
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public final class DouglasPeuker
-{
-    public static final double EPSILON = 1e-4;
-
-    private DouglasPeuker() {
-    }
-
-    public static List<XY> simplify(List<XY> input) {
-        return simplify(input, EPSILON);
-    }
-
-    public static List<XY> simplify(List<XY> input, double epsilon) {
-
-        int N = input.size();
-
-        if (N < 3) {
-            return new ArrayList<XY>(input);
-        }
-
-        List<XY> simplified = recursiveSimplify(input, 0, N-1, epsilon);
-
-        List<XY> output = new ArrayList<XY>(simplified.size()+2);
-        output.add(input.get(0));
-        output.addAll(simplified);
-        output.add(input.get(N-1));
-
-        return output;
-    }
-
-    private static List recursiveSimplify(
-        List<XY> input,
-        int      start,
-        int      end,
-        double   epsilon
-    ) {
-        XY a = input.get(start);
-        XY b = input.get(end);
-
-        // Normal of hesse normal form.
-        XY n = new XY(b).sub(a).ortho().normalize();
-
-        // distance offset of the hesse normal form.
-        double d = n.lineOffset(a);
-
-        double maxDist = -Double.MAX_VALUE;
-        int maxIdx = -1;
-
-        for (int i = start+1; i < end; ++i) {
-            double dist = Math.abs(n.dot(input.get(i)) + d);
-            if (dist > maxDist) {
-                maxDist = dist;
-                maxIdx  = i;
-            }
-        }
-
-        if (maxDist < epsilon) {
-            // All points between a and b can be ignored.
-            return Collections.<XY>emptyList();
-        }
-
-        // Split by input[maxIdx].
-        List<XY> before = recursiveSimplify(input, start, maxIdx, epsilon);
-        List<XY> after  = recursiveSimplify(input, maxIdx, end, epsilon);
-
-        List<XY> output = new ArrayList<XY>(before.size()+1+after.size());
-        output.addAll(before);
-        output.add(input.get(maxIdx));
-        output.addAll(after);
-
-        return output;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/backend/src/main/java/org/dive4elements/river/utils/EpsilonComparator.java	Thu Sep 04 13:00:55 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.utils;
-
-import java.util.Comparator;
-import java.io.Serializable;
-
-/** Comparator with some tolerance (epsilon). */
-public class EpsilonComparator implements Comparator<Double>, Serializable
-{
-    public static final double EPSILON = 1e-4;
-
-    /** Ready-made comparator with 1e-4 tolerance. */
-    public static final EpsilonComparator CMP = new EpsilonComparator(EPSILON);
-
-    private double epsilon;
-
-    public EpsilonComparator(double epsilon) {
-        this.epsilon = epsilon;
-    }
-
-    @Override
-    public int compare(Double a, Double b) {
-        double diff = a - b;
-        if (diff < -epsilon) return -1;
-        if (diff >  epsilon) return +1;
-        return 0;
-    }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/backend/src/main/java/org/dive4elements/river/utils/StringUtil.java	Thu Sep 04 13:00:55 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,828 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
- * Software engineering by Intevation GmbH
- *
- * This file is Free Software under the GNU AGPL (>=v3)
- * and comes with ABSOLUTELY NO WARRANTY! Check out the
- * documentation coming with Dive4Elements River for details.
- */
-
-package org.dive4elements.river.utils;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Locale;
-
-import java.net.URLEncoder;
-import java.net.URLDecoder;
-
-import java.io.UnsupportedEncodingException;
-import java.io.IOException;
-import java.io.BufferedReader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.PrintWriter;
-
-
-public final class StringUtil {
-    final static String NUMBER_SEPERATOR = ";";
-    final static String LINE_SEPERATOR = ":";
-
-    private StringUtil() {
-    }
-
-    public static final String double2DArrayToString(double[][] values) {
-
-        if (values == null) {
-            throw new IllegalArgumentException("keine double[][]-Werte");
-        }
-
-        StringBuilder strbuf = new StringBuilder();
-
-        for (int i=0; i < values.length; i++) {
-            if (i>0) {
-                strbuf.append(LINE_SEPERATOR);
-            }
-            for (int j=0; j < values[i].length; j++) {
-                if (j > 0) {
-                    strbuf.append(NUMBER_SEPERATOR);
-                }
-                strbuf.append(values[i][j]);
-            }
-        }
-
-        return strbuf.toString();
-    }
-
-    public static final double[][] stringToDouble2DArray(String str) {
-        if (str == null || str.length() == 0) {
-            return null;
-        }
-
-        String[] lineSplit = str.split(LINE_SEPERATOR);
-        double[][] array2D = new double[lineSplit.length][];
-        for (int i=0; i < lineSplit.length; i++) {
-            String[] numberSplit =  lineSplit[i].split(NUMBER_SEPERATOR);
-
-            double[] numbers = new double[numberSplit.length];
-            for (int j=0; j < numberSplit.length; j++) {
-                numbers[j] = Double.valueOf(numberSplit[j]).doubleValue();
-            }
-
-            array2D[i] = numbers;
-        }
-
-        return array2D;
-    }
-
-    /**
-     * Remove first occurrence of "[" and "]" (if both do occur).
-     * @param value String to be stripped of [] (might be null).
-     * @return input string but with [ and ] removed, or input string if no
-     *         brackets were found.
-     */
-    public static final String unbracket(String value) {
-        // null- guard
-        if (value == null) return value;
-
-        int start = value.indexOf("[");
-        int end   = value.indexOf("]");
-
-        if (start < 0 || end < 0) {
-            return value;
-        }
-
-        value = value.substring(start + 1, end);
-
-        return value;
-    }
-
-
-    /**
-     * From "Q=1" make "W(Q=1)".
-     * @return original string wraped in "W()" if it contains a "Q", original
-     *         string otherwise.
-     */
-    public static String wWrap(String wOrQ) {
-        return (wOrQ != null && wOrQ.indexOf("Q") >=0)
-               ? "W(" + wOrQ + ")"
-               : wOrQ;
-        }
-
-
-    public static final String [] splitLines(String s) {
-        if (s == null) {
-            return null;
-        }
-        ArrayList<String> list = new ArrayList<String>();
-
-        BufferedReader in = null;
-
-        try {
-            in =
-                new BufferedReader(
-                new StringReader(s));
-
-            String line;
-
-            while ((line = in.readLine()) != null) {
-                list.add(line);
-            }
-        }
-        catch (IOException ioe) {
-            return null;
-        }
-        finally {
-            if (in != null)
-                try {
-                    in.close();
-                }
-                catch (IOException ioe) {}
-        }
-
-        return list.toArray(new String[list.size()]);
-    }
-
-    public static final String concat(String [] s) {
-        return concat(s, null);
-    }
-
-    public static final String concat(String [] s, String glue) {
-        if (s == null) {
-            return null;
-        }
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < s.length; ++i) {
-            if (i > 0 && glue != null) {
-                sb.append(glue);
-            }
-            sb.append(s[i]);
-        }
-        return sb.toString();
-    }
-
-    public static final String [] splitAfter(String [] src, int N) {
-        if (src == null) {
-            return null;
-        }
-
-        ArrayList<String> list = new ArrayList<String>(src.length);
-        for (int i = 0; i < src.length; ++i) {
-            String s = src[i];
-            int R;
-            if (s == null || (R = s.length()) == 0) {
-                list.add(s);
-            }
-            else {
-                while (R > N) {
-                    list.add(s.substring(0, N));
-                    s = s.substring(N);
-                    R = s.length();
-                }
-                list.add(s);
-            }
-        }
-        return list.toArray(new String[list.size()]);
-    }
-
-    public static final String [] splitQuoted(String s) {
-        return splitQuoted(s, '"');
-    }
-
-    public static final String[] fitArray(String [] src, String [] dst) {
-        if (src == null) {
-            return dst;
-        }
-        if (dst == null) {
-            return src;
-        }
-
-        if (src.length == dst.length) {
-            return src;
-        }
-
-        System.arraycopy(src, 0, dst, 0, Math.min(dst.length, src.length));
-
-        return dst;
-    }
-
-    public static final String [] splitQuoted(String s, char quoteChar) {
-        if (s == null) {
-            return null;
-        }
-        ArrayList<String> l = new ArrayList<String>();
-        int mode = 0, last_mode = 0;
-        StringBuilder sb = new StringBuilder();
-        for (int N = s.length(), i = 0; i < N; ++i) {
-            char c = s.charAt(i);
-            switch (mode) {
-                case 0: // unquoted mode
-                    if (c == quoteChar) {
-                        mode = 1; // to quoted mode
-                        if (sb.length() > 0) {
-                            l.add(sb.toString());
-                            sb.setLength(0);
-                        }
-                    }
-                    else if (c == '\\') {
-                        last_mode = 0;
-                        mode = 2; // escape mode
-                    }
-                    else if (!Character.isWhitespace(c)) {
-                        sb.append(c);
-                    }
-                    else if (sb.length() > 0) {
-                        l.add(sb.toString());
-                        sb.setLength(0);
-                    }
-                    break;
-                case 1: // quote mode
-                    if (c == '\\') {
-                        last_mode = 1;
-                        mode = 2; // escape mode
-                    }
-                    else if (c == quoteChar) { // leave quote mode
-                        l.add(sb.toString());
-                        sb.setLength(0);
-                        mode = 0; // to unquoted mode
-                    }
-                    else {
-                        sb.append(c);
-                    }
-                    break;
-                case 2: // escape mode
-                    sb.append(c);
-                    mode = last_mode;
-                    break;
-            }
-        }
-        if (sb.length() > 0) {
-            l.add(sb.toString());
-        }
-        return l.toArray(new String[l.size()]);
-    }
-
-    public static final String [] splitUnique(String s) {
-        return splitUnique(s, "[\\s,]+");
-    }
-
-    public static final String [] splitUnique(String s, String sep) {
-        return s != null ? unique(s.split(sep)) : null;
-    }
-
-    public static final String [] unique(String [] str) {
-        if (str == null || str.length == 1) {
-            return str;
-        }
-
-        Arrays.sort(str);
-
-        for (int i = 1; i < str.length; ++i)
-            if (str[i].equals(str[i-1])) {
-                ArrayList<String> list = new ArrayList<String>(str.length);
-
-                for (int j = 0; j < i; ++j) {
-                    list.add(str[j]);
-                }
-
-                String last = str[i];
-
-                for (++i; i < str.length; ++i)
-                    if (!last.equals(str[i])) {
-                        list.add(last = str[i]);
-                    }
-
-                return list.toArray(new String[list.size()]);
-            }
-
-        return str;
-    }
-
-    public static final String [] ensureEmptyExistence(String [] str) {
-        if (str == null) {
-            return null;
-        }
-
-        for (int i = 0; i < str.length; ++i)
-            if (str[i].length() == 0) {
-                if (i != 0) { // copy to front
-                    String t = str[0];
-                    str[0] = str[i];
-                    str[i] = t;
-                }
-                return str;
-            }
-
-        String [] n = new String[str.length+1];
-        n[0] = "";
-        System.arraycopy(str, 0, n, 1, str.length);
-        return n;
-    }
-
-    public static final String ensureWidthPadLeft(String s, int width, char pad) {
-        int N = s.length();
-        if (N >= width) {
-            return s;
-        }
-        StringBuilder sb = new StringBuilder(width);
-        for (; N < width; ++N) {
-            sb.append(pad);
-        }
-        sb.append(s);
-        return sb.toString();
-    }
-
-    public static final String [] splitWhiteSpaceWithNAsPad(
-        String s,
-        int    N,
-        String pad
-    ) {
-        if (s == null) {
-            return null;
-        }
-
-        boolean copyChars = true;
-        int     count     = 0; // number of WS
-
-        int S = s.length();
-
-        ArrayList<String> parts = new ArrayList<String>();
-
-        StringBuilder part = new StringBuilder(S);
-
-        for (int i = 0; i < S; ++i) {
-            char c = s.charAt(i);
-            if (copyChars) { // char mode
-                if (Character.isWhitespace(c)) {
-                    if (part.length() > 0) {
-                        parts.add(part.toString());
-                        part.setLength(0);
-                    }
-                    count     = 1;
-                    copyChars = false; // to WS mode
-                }
-                else {
-                    part.append(c);
-                }
-            }
-            else { // counting WS
-                if (Character.isWhitespace(c)) {
-                    ++count;
-                }
-                else {
-                    while (count >= N) {// enough to insert pad?
-                        parts.add(pad);
-                        count -= N;
-                    }
-                    part.append(c);
-                    count     = 0;
-                    copyChars = true; // back to char mode
-                }
-            }
-        } // for all chars
-
-        if (copyChars) {
-            if (part.length() > 0) {
-                parts.add(part.toString());
-            }
-        }
-        else {
-            while (count >= N) { // enough to insert pad?
-                parts.add(pad);
-                count -= N;
-            }
-        }
-
-        return parts.toArray(new String[parts.size()]);
-    }
-
-    public static final String encodeURL(String url) {
-        try {
-            return url != null
-                   ? URLEncoder.encode(url, "UTF-8")
-                   : "";
-        }
-        catch (UnsupportedEncodingException usee) {
-            throw new RuntimeException(usee.getLocalizedMessage());
-        }
-    }
-
-    public static final String decodeURL(String url) {
-        try {
-            return url != null
-                   ? URLDecoder.decode(url, "UTF-8")
-                   : "";
-        }
-        catch (UnsupportedEncodingException usee) {
-            throw new RuntimeException(usee.getLocalizedMessage());
-        }
-    }
-
-    public static final boolean isEmpty(String s) {
-        return s == null || s.length() == 0;
-    }
-
-    public static final String empty(String s) {
-        return s == null ? "" : s;
-    }
-
-
-    public static final String trim(String s) {
-        return s != null ? s.trim() : null;
-    }
-
-    public static final String uniqueWhitespaces(String s) {
-        if (s == null) {
-            return null;
-        }
-
-        boolean wasWS = false;
-        StringBuilder sb = new StringBuilder();
-
-        for (int N = s.length(), i = 0; i < N; ++i) {
-            char c = s.charAt(i);
-            if (Character.isWhitespace(c)) {
-                if (!wasWS) {
-                    sb.append(c);
-                    wasWS = true;
-                }
-            }
-            else {
-                sb.append(c);
-                wasWS = false;
-            }
-        }
-
-        return sb.toString();
-    }
-
-    public static final String replaceNewlines(String s) {
-        return s == null
-               ? null
-               : s.replace('\r', ' ').replace('\n', ' ');
-    }
-
-    /*
-    public static final String quoteReplacement(String s) {
-
-        if (s == null || (s.indexOf('\\') == -1 && s.indexOf('$') == -1))
-            return s;
-
-        StringBuilder sb = new StringBuilder();
-
-        for (int N = s.length(), i = 0; i < N; ++i) {
-            char c = s.charAt(i);
-            if (c == '\\' || c == '$') sb.append('\\');
-            sb.append(c);
-        }
-
-        return sb.toString();
-    }
-    */
-
-    public static final String quoteReplacement(String s) {
-
-        if (s == null) {
-            return null;
-        }
-
-        for (int N = s.length(), i = 0; i < N; ++i) { // plain check loop
-            char c = s.charAt(i);
-            if (c == '$' || c == '\\') { // first special -> StringBuilder
-                StringBuilder sb = new StringBuilder(s.substring(0, i))
-                .append('\\')
-                .append(c);
-                for (++i; i < N; ++i) { // build StringBuilder with rest
-                    if ((c = s.charAt(i)) == '$' || c == '\\') {
-                        sb.append('\\');
-                    }
-                    sb.append(c);
-                }
-                return sb.toString();
-            }
-        }
-
-        return s;
-    }
-
-    public static final String repeat(String what, int times) {
-        return repeat(what, times, new StringBuilder()).toString();
-    }
-
-    public static final StringBuilder repeat(String what, int times, StringBuilder sb) {
-        while (times-- > 0) {
-            sb.append(what);
-        }
-        return sb;
-    }
-
-    /**
-     * Returns the file name without extension.
-     */
-    public static final String cutExtension(String s) {
-        if (s == null) {
-            return null;
-        }
-        int dot = s.lastIndexOf('.');
-        return dot >= 0
-               ? s.substring(0, dot)
-               : s;
-    }
-
-    public static final String extension(String s) {
-        if (s == null) {
-            return null;
-        }
-        int dot = s.lastIndexOf('.');
-        return dot >= 0
-               ? s.substring(dot+1)
-               : s;
-    }
-
-    public static final String [] splitExtension(String x) {
-        if (x == null) {
-            return null;
-        }
-        int i = x.lastIndexOf('.');
-        return i < 0
-               ? new String[] { x, null }
-               : new String[] { x.substring(0, Math.max(0, i)), x.substring(i+1).toLowerCase() };
-    }
-
-    public static String entityEncode(String s) {
-        if (s == null || s.length() == 0) {
-            return s;
-        }
-
-        StringBuilder sb = new StringBuilder();
-        for (int i=0, N =s.length(); i < N; i++) {
-            char c = s.charAt(i);
-            switch (c) {
-                case '<':
-                    sb.append("&lt;");
-                    break;
-                case '>':
-                    sb.append("&gt;");
-                    break;
-                case '&':
-                    sb.append("&amp;");
-                    break;
-                default:
-                    sb.append(c);
-            }
-        }
-        return sb.toString();
-    }
-
-    public static String entityDecode(String s) {
-        if (s == null || s.length() == 0) {
-            return s;
-        }
-
-        boolean amp = false;
-        StringBuilder sb = new StringBuilder();
-        StringBuilder ampbuf = new StringBuilder();
-        for (int i=0, N =s.length(); i < N; i++) {
-            char c = s.charAt(i);
-            if (amp) {
-                if (c == ';') {
-                    amp = false;
-                    String str = ampbuf.toString();
-                    ampbuf.setLength(0);
-                    if (str.equals("lt")) {
-                        sb.append('<');
-                    }
-                    else if (str.equals("gt")) {
-                        sb.append('>');
-                    }
-                    else if (str.equals("amp")) {
-                        sb.append('&');
-                    }
-                    else {
-                        sb.append('&').append(str).append(';');
-                    }
-                }
-                else {
-                    ampbuf.append(c);
-                }
-            }
-            else if (c=='&') {
-                amp = true;
-            }
-            else {
-                sb.append(c);
-            }
-
-        }
-        return sb.toString();
-    }
-
-    public static final String quote(String s) {
-        return quote(s, '"');
-    }
-
-    public static final String quote(String s, char quoteChar) {
-        if (s == null) {
-            return null;
-        }
-
-        int N = s.length();
-
-        if (N == 0)
-            return new StringBuilder(2)
-                   .append(quoteChar)
-                   .append(quoteChar)
-                   .toString();
-
-        StringBuilder sb = null;
-
-        int i = 0;
-
-        for (; i < N; ++i) {
-            char c = s.charAt(i);
-
-            if (Character.isWhitespace(c)) {
-                sb = new StringBuilder()
-                .append(quoteChar)
-                .append(s.substring(0, i+1));
-                break;
-            }
-            else if (c == quoteChar) {
-                sb = new StringBuilder()
-                .append(quoteChar)
-                .append(s.substring(0, i))
-                .append('\\')
-                .append(quoteChar);
-                break;
-            }
-        }
-
-        if (sb == null) {
-            return s;
-        }
-
-        for (++i; i < N; ++i) {
-            char c = s.charAt(i);
-            if (c == quoteChar || c == '\\') {
-                sb.append('\\');
-            }
-
-            sb.append(c);
-        }
-
-        return sb.append(quoteChar).toString();
-    }
-
-    /*
-    public static String sprintf(String format, Object... args) {
-        return sprintf(null, format, args);
-    }
-    */
-
-    public static String sprintf(Locale locale, String format, Object ... args) {
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        pw.printf(locale, format, args);
-        pw.flush();
-        return sw.toString();
-    }
-
-
-    public static void testQuote() {
-        System.err.println("testing quote:");
-
-        String cases []  = {
-            "",          "''",
-            "test",      "test",
-            "test test", "'test test'",
-            "  test",    "'  test'",
-            "test   ",   "'test   '",
-            " test ",    "' test '",
-            "'test",     "'\\'test'",
-            "'",         "'\\''",
-            " ' ' ",     "' \\' \\' '",
-            "te'st",     "'te\\'st'"
-        };
-
-        int failed = 0;
-
-        for (int i = 0; i < cases.length; i += 2) {
-            String in  = cases[i];
-            String out = cases[i+1];
-
-            String res = quote(in, '\'');
-            if (!res.equals(out)) {
-                ++failed;
-                System.err.println(
-                    "quote failed on: >" + in +
-                    "< result: >" + res +
-                    "< expected: >" + out + "<");
-            }
-        }
-
-        int T = cases.length/2;
-
-        System.err.println("tests total: "  + T);
-        System.err.println("tests failed: " + failed);
-        System.err.println("tests passed: " + (T - failed));
-    }
-
-    public static void testQuoteReplacement() {
-        System.err.println("testing quoteReplacement:");
-
-        String cases []  = {
-            "",          "",
-            "test",      "test",
-            "$",         "\\$",
-            "\\",        "\\\\",
-            "\\$",       "\\\\\\$",
-            "test\\$",   "test\\\\\\$",
-            "\\test",    "\\\\test",
-            "test$",     "test\\$",
-            "test$test", "test\\$test",
-            "$test$",    "\\$test\\$"
-        };
-
-        int failed = 0;
-
-        for (int i = 0; i < cases.length; i += 2) {
-            String in  = cases[i];
-            String out = cases[i+1];
-
-            String res = quoteReplacement(in);
-            if (!res.equals(out)) {
-                ++failed;
-                System.err.println(
-                    "quoteReplacement failed on: '" + in +
-                    "' result: '" + res +
-                    "' expected: '" + out + "'");
-            }
-        }
-
-        int T = cases.length/2;
-
-        System.err.println("tests total: "  + T);
-        System.err.println("tests failed: " + failed);
-        System.err.println("tests passed: " + (T - failed));
-    }
-
-    public static void testStringArray2D() {
-        int total = 0;
-        int fail = 0;
-        int passed = 0;
-
-        System.err.println("testing StringArray2D:");
-
-        double[][] testarray = {{1.0, 2.0, 3.0},
-            {1.1, 2.1, 3.1},
-            {100.2, 200.2}
-        };
-        String str = double2DArrayToString(testarray);
-
-        total += 1;
-        if (str.equals("1.0;2.0;3.0:1.1;2.1;3.1:100.2;200.2")) {
-            passed +=1;
-        }
-        else {
-            fail +=1;
-            System.err.println("Der Ergebnis-String ist nicht richtig:");
-            System.err.println(str);
-        }
-
-
-
-        double[][] testarray2 = stringToDouble2DArray(str);
-        boolean failed = false;
-
-        total +=1;
-        for (int i=0; i < testarray.length; i++)
-            for (int j=0; j < testarray[i].length; j++)
-                if (testarray[i][j] != testarray2[i][j]) {
-                    System.err.println("Test scheitert bei i=" +i +" j=" +j);
-                    System.err.println("alter Wert=" + testarray[i][j] +" neuer Wert=" +testarray2[i][j]);
-                    failed = true;
-                }
-        if (failed) {
-            fail +=1;
-        }
-        else {
-            passed +=1;
-        }
-        System.err.println("tests total: "+ total);
-        System.err.println("tests failed: "+ fail);
-        System.err.println("tests passed: "+ passed);
-    }
-
-    public static void main(String [] args) {
-
-        testQuoteReplacement();
-        testQuote();
-        testStringArray2D();
-    }
-
-    /** Check for occurence of needle in hay, converting both to lowercase
-     * to be ignorant of cases. */
-    public static boolean containsIgnoreCase(String hay, String needle) {
-        return hay.toLowerCase().contains(needle.toLowerCase());
-    }
-}
-// end of file

http://dive4elements.wald.intevation.org