diff --git a/nb-configuration.xml b/nb-configuration.xml
index 1bd992ca9ddc25bbebf62272ea26f5c5ceb51d77..2f11ad2cceb58419d0c43844e6368745831a97c2 100755
--- a/nb-configuration.xml
+++ b/nb-configuration.xml
@@ -26,5 +26,6 @@ Any value defined here will override the pom.xml file value but is only applicab
         <org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>WildFly</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
         <org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language>
         <org-netbeans-modules-maven-jaxws._5f_C_5f_DMIWeatherService_2e_svc>https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?wsdl</org-netbeans-modules-maven-jaxws._5f_C_5f_DMIWeatherService_2e_svc>
+        <netbeans.compile.on.save>none</netbeans.compile.on.save>
     </properties>
 </project-shared-configuration>
diff --git a/src/jax-ws-catalog.xml b/src/jax-ws-catalog.xml
index c074fd31684adeb88bef92ad56e99be552150899..f6401c8f6762828e08fbbb03755addae0840bbae 100644
--- a/src/jax-ws-catalog.xml
+++ b/src/jax-ws-catalog.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
     <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.xml"/>
+    <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?singleWsdl" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.singlewsdl.wsdl"/>
     <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?wsdl" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.wsdl"/>
     <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?xsd=xsd0" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.xsd_xsd0.xsd"/>
     <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?xsd=xsd1" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.xsd_xsd1.xsd"/>
     <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?xsd=xsd2" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.xsd_xsd2.xsd"/>
     <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?xsd=xsd3" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.xsd_xsd3.xsd"/>
     <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?xsd=xsd4" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.xsd_xsd4.xsd"/>
-    <system systemId="https://dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc?singleWsdl" uri="wsdl/dmiweatherservice-plant.dlbr.dk/DMIWeatherService.svc.singlewsdl.wsdl"/>
 </catalog>
\ No newline at end of file
diff --git a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
index 78c6e42ce60a0b75d6803ccdc5aa05715cfc3872..255cbaf060bea1ef562b31c305d4ae6b8dc1df16 100755
--- a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
+++ b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
@@ -54,6 +54,7 @@ public class VIPSLogicApplication extends Application
         resources.add(no.nibio.vips.logic.modules.applefruitmoth.AppleFruitMothService.class);
         resources.add(no.nibio.vips.logic.service.ObservationService.class);
         resources.add(no.nibio.vips.logic.service.WeatherProxyService.class);
+        resources.add(no.nibio.vips.logic.service.ModelFormService.class);
         resources.add(no.nibio.vips.logic.service.JacksonConfig.class);
         //resources.add(no.nibio.vips.coremanager.service.ManagerResourceImpl.class);
     }
@@ -70,6 +71,7 @@ public class VIPSLogicApplication extends Application
         resources.add(no.nibio.vips.logic.modules.roughage.RoughageService.class);
         resources.add(no.nibio.vips.logic.service.JacksonConfig.class);
         resources.add(no.nibio.vips.logic.service.LogicService.class);
+        resources.add(no.nibio.vips.logic.service.ModelFormService.class);
         resources.add(no.nibio.vips.logic.service.ObservationService.class);
         resources.add(no.nibio.vips.logic.service.VIPSMobileService.class);
         resources.add(no.nibio.vips.logic.service.WeatherProxyService.class);
diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java
index 9f5dde0951e54e4e1423b5eb197fc46fd3ae715c..8c169a334ec470129cd3655e3b3555279826dadb 100755
--- a/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java
+++ b/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java
@@ -120,7 +120,7 @@ public class LoginController extends HttpServlet {
                 if(user != null)
                 {
                     request.getSession().setAttribute("user", user);
-                    UUID uUUID = this.handleRememberUser(request, response, user);
+                    UUID uUUID = this.handleRememberUser(request, response, user, returnUUID);
                     if(returnUUID)
                     {
                         nextPage += (nextPage.contains("?") ? "&": "?") + "returnUUID=" + uUUID.toString();
@@ -193,7 +193,7 @@ public class LoginController extends HttpServlet {
                     if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_APPROVED))
                     {
                         request.getSession().setAttribute("user", user);
-                        UUID uUUID = this.handleRememberUser(request, response, user);
+                        UUID uUUID = this.handleRememberUser(request, response, user, returnUUID);
                         if(returnUUID)
                         {
                             nextPage += (nextPage.contains("?") ? "&": "?") + "returnUUID=" + uUUID.toString();
@@ -282,7 +282,7 @@ public class LoginController extends HttpServlet {
             if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_APPROVED))
             {
                 request.getSession().setAttribute("user", user);
-                UUID uUUID = this.handleRememberUser(request, response, user);
+                UUID uUUID = this.handleRememberUser(request, response, user, returnUUID);
                 // All is well, return object
                 ObjectMapper mapper = new ObjectMapper();
                 user.setUserUuid(uUUID);
@@ -362,20 +362,23 @@ public class LoginController extends HttpServlet {
      * @param response
      * @param user 
      */
-    private UUID handleRememberUser(HttpServletRequest request, HttpServletResponse response, VipsLogicUser user)
+    private UUID handleRememberUser(HttpServletRequest request, HttpServletResponse response, VipsLogicUser user, Boolean returnUUID)
     {
         
         String rememberUser = request.getParameter("rememberUser") != null ? 
                 request.getParameter("rememberUser") 
                 : (String) request.getSession().getAttribute("rememberUser");
         request.getSession().removeAttribute("rememberUser");
-        if(rememberUser != null && rememberUser.equals("on"))
+        if(returnUUID || (rememberUser != null && rememberUser.equals("on")))
         {
             UserUuid uUUID = SessionControllerGetter.getUserBean().createAndPersistUserUuid(user);
-            Cookie rememberedUser = new Cookie("rememberedUser", uUUID.getUserUuidPK().getUserUuid().toString());
-            rememberedUser.setPath("/");
-            rememberedUser.setMaxAge(Globals.DEFAULT_UUID_VALIDITY_DURATION_DAYS * 24 * 60 * 60);
-            response.addCookie(rememberedUser);
+            if(rememberUser != null && rememberUser.equals("on"))
+            {
+                Cookie rememberedUser = new Cookie("rememberedUser", uUUID.getUserUuidPK().getUserUuid().toString());
+                rememberedUser.setPath("/");
+                rememberedUser.setMaxAge(Globals.DEFAULT_UUID_VALIDITY_DURATION_DAYS * 24 * 60 * 60);
+                response.addCookie(rememberedUser);
+            }
             return uUUID.getUserUuidPK().getUserUuid();
         }
         else
diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java
index d98f5e6c7c126e49ab0830417d5410cf640b01fb..fc34a6f0f4b4043a49d4cfd09f504c34f99532da 100755
--- a/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java
+++ b/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java
@@ -311,26 +311,28 @@ public class PointOfInterestController extends HttpServlet {
                             weatherStation = SessionControllerGetter.getPointOfInterestBean().storeWeatherStation(weatherStation);
                             
                             Map<String, FormField> externalResourceIdentifiers = formValidation.getMultipleMapFormFields().get("externalResourceIdentifier");
-                            for(String key:externalResourceIdentifiers.keySet())
+                            if(externalResourceIdentifiers != null)
                             {
-                                Integer externalResourceId = Integer.valueOf(key);
-                                FormField identifierField = externalResourceIdentifiers.get(key);
-                                if(identifierField.getWebValue() == null || identifierField.getWebValue().isEmpty())
+                                for(String key:externalResourceIdentifiers.keySet())
                                 {
-                                    // We delete existing if unset
-                                    SessionControllerGetter.getPointOfInterestBean().deletePointOfInterestExternalResource(weatherStation.getPointOfInterestId(), externalResourceId);
-                                }
-                                else
-                                {
-                                    
-                                    PointOfInterestExternalResource poiExternalResource = new PointOfInterestExternalResource();
-                                    PointOfInterestExternalResourcePK pk = new PointOfInterestExternalResourcePK(weatherStation.getPointOfInterestId(), externalResourceId);
-                                    poiExternalResource.setPointOfInterestExternalResourcePK(pk);
-                                    poiExternalResource.setResourceIdentifier(identifierField.getWebValue());
-                                    SessionControllerGetter.getPointOfInterestBean().storePointOfInterestExternalResource(poiExternalResource);
+                                    Integer externalResourceId = Integer.valueOf(key);
+                                    FormField identifierField = externalResourceIdentifiers.get(key);
+                                    if(identifierField.getWebValue() == null || identifierField.getWebValue().isEmpty())
+                                    {
+                                        // We delete existing if unset
+                                        SessionControllerGetter.getPointOfInterestBean().deletePointOfInterestExternalResource(weatherStation.getPointOfInterestId(), externalResourceId);
+                                    }
+                                    else
+                                    {
+
+                                        PointOfInterestExternalResource poiExternalResource = new PointOfInterestExternalResource();
+                                        PointOfInterestExternalResourcePK pk = new PointOfInterestExternalResourcePK(weatherStation.getPointOfInterestId(), externalResourceId);
+                                        poiExternalResource.setPointOfInterestExternalResourcePK(pk);
+                                        poiExternalResource.setResourceIdentifier(identifierField.getWebValue());
+                                        SessionControllerGetter.getPointOfInterestBean().storePointOfInterestExternalResource(poiExternalResource);
+                                    }
                                 }
                             }
-                            
                             // Redirect to form
                             response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://")
                                 .append(ServletUtil.getServerName(request))
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java
index 71d487cfc981054d8e79bf1db1c9570465f6c158..f06f13638eba40806db40747f377ef80f02bf261 100755
--- a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java
@@ -324,7 +324,7 @@ public class ForecastBean {
                 .setParameter("organizationIds", organizationIds)
                 .getResultList();
         
-        if(!organizationUsers.isEmpty())
+        if(!organizationUsers.isEmpty() && ! modelIds.isEmpty())
         {
             return em
                     .createNamedQuery("ForecastConfiguration.findByVipsLogicUserIdsAndModelIdsAndDate")
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java
index 8f1534f66f9046e2ed3fb78086db4697fafcb8ca..30180926c14fda836a4e30867a0db480bce741f7 100755
--- a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java
@@ -30,7 +30,6 @@ import de.micromata.opengis.kml.v_2_2_0.Point;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.ResourceBundle;
 import java.util.Set;
@@ -252,8 +251,14 @@ public class PointOfInterestBean {
      * @return 
      */
     public List<PointOfInterestWeatherStation> getWeatherstationsForOrganization(Organization organization, Boolean active) {
+        
+        if(organization == null)
+        {
+            return new ArrayList<>();
+        }
         // Avoid nulls
         active = active == null ? true : active;
+        
         List<PointOfInterestWeatherStation> retVal = em.createNamedQuery("PointOfInterestWeatherStation.findByActivityAndOrganizationId", PointOfInterestWeatherStation.class)
                                                 .setParameter("organizationId", organization)
                                                 .setParameter("active", active)
@@ -455,5 +460,10 @@ public class PointOfInterestBean {
                 
     }
 
+    public WeatherStationDataSource getWeatherStationDataSource(String dataSourceName){
+        return em.createNamedQuery("WeatherStationDataSource.findByName", WeatherStationDataSource.class)
+                .setParameter("name", dataSourceName)
+                .getSingleResult();
+    }
     
 }
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java b/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java
index 7fa9924f042dc7277bcc80c4ca3ff39a94a10505..2356256e90efc92919c68920323f4007b02f4bb3 100755
--- a/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java
@@ -198,17 +198,22 @@ public class SchedulingBean {
         SchedulingPattern everyNightPattern = new SchedulingPattern("0 6 * * *");
         deleteAllExpiredUserUuidsCollector.getTasks().add(everyNightPattern, VipsLogicTaskFactory.createVipsLogicTask(VipsLogicTaskFactory.DELETE_ALL_EXPIRED_UUIDS_TASK));
         
-        // Sendt forecast notifications
+        // Send forecast notifications
         VIPSLogicTaskCollector sendForecastNotificationsCollector = new VIPSLogicTaskCollector(-1);
         SchedulingPattern morningAndAfternoonPattern = new SchedulingPattern("45 6,12 * * *");
         sendForecastNotificationsCollector.getTasks().add(morningAndAfternoonPattern, VipsLogicTaskFactory.createVipsLogicTask(VipsLogicTaskFactory.SEND_FORECAST_EVENT_NOTIFICATIONS_TASK));
         
+        // Run grid models
+        VIPSLogicTaskCollector runGridModelsCollector = new VIPSLogicTaskCollector(-1);
+        runGridModelsCollector.getTasks().add(everyNightPattern, VipsLogicTaskFactory.createVipsLogicTask(VipsLogicTaskFactory.RUN_GRID_MODELS_TASK));
+        
         List<TaskCollector> definedTasks = new ArrayList<>();
         definedTasks.add(modelRunCollector);
         definedTasks.add(cacheHandlerCollector);
         definedTasks.add(summariesCollector);
         definedTasks.add(deleteAllExpiredUserUuidsCollector);
-        definedTasks.add((sendForecastNotificationsCollector));
+        definedTasks.add(sendForecastNotificationsCollector);
+        definedTasks.add(runGridModelsCollector);
         return definedTasks;
     }
     
diff --git a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java
index bc2e135ee21b184ba6cc08b65ce1f264c77f686c..25ca99b446296785deaa2b8683a2ad46eba40c98 100755
--- a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java
+++ b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java
@@ -721,14 +721,18 @@ public class UserBean {
         }
     }
     
-    // TODO: Put in config file?
-    private final static String[] USER_COUNTRY_CODES = {"NO","SE","BA","LV","US"};
-    
     public List<Country> getUserCountries()
     {
-        return em.createNamedQuery("Country.findByCountryCodes")
-                .setParameter("countryCodes",Arrays.asList(UserBean.USER_COUNTRY_CODES))
-                .getResultList();
+        try
+        {
+            return em.createNamedQuery("Country.findByCountryCodes")
+                    .setParameter("countryCodes",Arrays.asList(System.getProperty("no.nibio.vips.logic.USER_COUNTRY_CODES").split(",")))
+                    .getResultList();
+        }
+        catch(NullPointerException ex)
+        {
+            return new ArrayList<>();
+        }
     }
 
     public List<OrganizationGroup> getOrganizationGroups(Organization organization) {
diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
index d2856d038f94bec0e2aab92dce020011e4bc75ef..de0e904122e95c3a264c86ab3a6ee1595fd14270 100755
--- a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
+++ b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java
@@ -44,7 +44,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 import java.util.List;
 import java.util.TimeZone;
 import javax.persistence.Transient;
+import no.nibio.vips.logic.util.IntegerArrayUserType;
 import no.nibio.vips.util.WeatherUtil;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
 
 /**
  * @copyright 2014-2016 <a href="http://www.nibio.no/">NIBIO</a>
@@ -53,6 +57,7 @@ import no.nibio.vips.util.WeatherUtil;
 @Entity
 @Table(name = "forecast_configuration")
 @XmlRootElement
+@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)})
 @NamedQueries({
     @NamedQuery(name = "ForecastConfiguration.findAll", query = "SELECT f FROM ForecastConfiguration f WHERE f.isPrivate = FALSE"),
     @NamedQuery(name = "ForecastConfiguration.findByForecastConfigurationId", query = "SELECT f FROM ForecastConfiguration f WHERE f.forecastConfigurationId = :forecastConfigurationId"),
@@ -117,6 +122,10 @@ public class ForecastConfiguration implements Serializable, Comparable {
     @Column(name = "is_private")
     private Boolean isPrivate;
     
+    @Type(type = "IntegerArray")
+    @Column(name = "grid_weather_station_point_of_interest_ids")
+    private Integer[] gridWeatherStationPointOfInterestIds;
+    
     @Transient
     private WeatherUtil weatherUtil;
     
@@ -391,4 +400,18 @@ public class ForecastConfiguration implements Serializable, Comparable {
     public void setIsPrivate(Boolean isPrivate) {
         this.isPrivate = isPrivate;
     }
+
+    /**
+     * @return the gridWeatherStationPointOfInterestIds
+     */
+    public Integer[] getGridWeatherStationPointOfInterestIds() {
+        return gridWeatherStationPointOfInterestIds;
+    }
+
+    /**
+     * @param gridWeatherStationPointOfInterestIds the gridWeatherStationPointOfInterestIds to set
+     */
+    public void setGridWeatherStationPointOfInterestIds(Integer[] gridWeatherStationPointOfInterestIds) {
+        this.gridWeatherStationPointOfInterestIds = gridWeatherStationPointOfInterestIds;
+    }
 }
diff --git a/src/main/java/no/nibio/vips/logic/entity/Organization.java b/src/main/java/no/nibio/vips/logic/entity/Organization.java
index 46397415e483e57315bc37d7600783dd08844168..b948b010975321fd4679785c194b5b5a810cfa09 100755
--- a/src/main/java/no/nibio/vips/logic/entity/Organization.java
+++ b/src/main/java/no/nibio/vips/logic/entity/Organization.java
@@ -83,6 +83,7 @@ public class Organization implements Serializable {
     private Integer defaultMapZoom;
     @Column(name = "default_time_zone")
     private String defaultTimeZone;
+    @JsonIgnore
     @Column(name = "default_vips_core_user_id")
     private Integer defaultVipsCoreUserId;
     @JsonIgnore
diff --git a/src/main/java/no/nibio/vips/logic/entity/PreparationType.java b/src/main/java/no/nibio/vips/logic/entity/PreparationType.java
index 12c2d1d413ed41604b38caa6a52eee8ac34ada49..623c0234587d2dca2e6cafe8716137b77fc37a5f 100755
--- a/src/main/java/no/nibio/vips/logic/entity/PreparationType.java
+++ b/src/main/java/no/nibio/vips/logic/entity/PreparationType.java
@@ -19,6 +19,7 @@
 
 package no.nibio.vips.logic.entity;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import java.io.Serializable;
 import java.util.Collection;
 import javax.persistence.Basic;
@@ -55,6 +56,7 @@ public class PreparationType implements Serializable {
     @Size(max = 255)
     @Column(name = "preparation_type_name")
     private String preparationTypeName;
+    @JsonIgnore
     @OneToMany(mappedBy = "preparationTypeId")
     private Collection<Preparation> preparationCollection;
 
diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java
index 971ac29c57481604e04eba28ec81de5c324aea16..c35279641cc1014f62c2aa79121dd59c00e7f506 100755
--- a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java
+++ b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java
@@ -60,7 +60,7 @@ public class MessagingBean {
     
     public void sendUniversalMessage(Message message)
     {
-        String msgDownloadUrlTpl = "https://www.vips-landbruk.no/";
+        String msgDownloadUrlTpl = "https://www.vips-landbruk.no/messages/" + message.getMessageId() + "/";
         // Create a universal message from the message
         // TODO: When UniversalMessage has changed, pick
         UniversalMessage uMessage = new UniversalMessage();
@@ -401,7 +401,7 @@ public class MessagingBean {
         {
             return;
         }
-        String msgDownloadUrlTpl = "https://www.vips-landbruk.no/";
+        String msgDownloadUrlTpl = "https://www.vips-landbruk.no/observations/" + observation.getObservationId() + "/";
         // Create a universal message from the message
         // TODO: When UniversalMessage has changed, pick
         UniversalMessage uMessage = new UniversalMessage();
@@ -412,7 +412,9 @@ public class MessagingBean {
         uMessage.setExpiresAt(cal.getTime());
         // For locale, we assume observer's language
         VipsLogicUser observer = em.find(VipsLogicUser.class, observation.getUserId());
-        uMessage.addMessageLocalVersion(observer.getPreferredLocale(), observation.getObservationHeading(), "", observation.getObservationText(), msgDownloadUrlTpl);
+        uMessage.addMessageLocalVersion(observer.getPreferredLocale(), observation.getObservationHeading(), "", 
+                observation.getObservationText()
+                , msgDownloadUrlTpl);
         
         // Find the suscribers, create distribution list
         uMessage.setDistributionList(this.getObservationNotificationSubscribers(observation));
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java
index 1776077651f8bbd4d1adf75dd781106c966a5564..92c07b8aae75114b2892e04652b4d70278160e34 100755
--- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java
@@ -31,11 +31,14 @@ import de.micromata.opengis.kml.v_2_2_0.Units;
 import de.micromata.opengis.kml.v_2_2_0.Vec2;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import javax.ejb.LocalBean;
 import javax.ejb.Stateless;
 import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
 import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
 import no.nibio.vips.logic.util.Globals;
 
 /**
@@ -54,6 +57,22 @@ public class AppleFruitMothBean {
         List<ObservationSite> sites = em.createNamedQuery("ObservationSite.findAll").getResultList();
         return sites;
     }
+    
+    public List<ObservationSite> getObservationSitesWithClusterCountLastUpdate(){
+        List<ObservationSite> sites = this.getObservationSites();
+        Query qu = em.createNativeQuery("SELECT max(last_updated) FROM applefruitmoth.observation_site_point_season_data osd WHERE osd.observation_site_point_id IN (SELECT observation_site_point_id FROM applefruitmoth.observation_site_point WHERE observation_site_id = :observationSiteId)");
+        sites.stream().forEach(site->{
+            qu.setParameter("observationSiteId", site.getObservationSiteId());
+            try
+            {
+                Date lastUpdated = (Date) qu.getSingleResult();
+                site.setLastUpdatedClusterCount(lastUpdated);
+            }
+            catch(NoResultException ex){}
+        });
+        
+        return sites;
+    }
 
     public ObservationSite getObservationSite(Integer observationSiteId) {
         return em.find(ObservationSite.class, observationSiteId);
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java
index c048e907b747dfe2c4904983027447bccdfa9efa..e4f3ca5df594f6b3d04c8c7f6137eef0e083a1b0 100755
--- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java
@@ -70,7 +70,7 @@ public class AppleFruitMothController extends HttpServlet {
             if(action == null)
             {
                 // Show map and list of existing stations
-                List<ObservationSite> observationSites = SessionControllerGetter.getAppleFruitMothBean().getObservationSites();
+                List<ObservationSite> observationSites = SessionControllerGetter.getAppleFruitMothBean().getObservationSitesWithClusterCountLastUpdate();
                 request.setAttribute("observationSites", observationSites);
                 request.getRequestDispatcher("/appleFruitMothStationList.ftl").forward(request, response);
             }
@@ -284,9 +284,11 @@ public class AppleFruitMothController extends HttpServlet {
                     ObservationSite observationSite = SessionControllerGetter.getAppleFruitMothBean().getObservationSite(observationSiteId);
                     
                     ObservationSiteSeasonCommonData seasonCommonData = observationSite.getCommonDataForSeason(currentSeason);
-                    seasonCommonData.setRemarks(request.getParameter("remarks"));
-                    SessionControllerGetter.getAppleFruitMothBean().storeObservationSitePointSeasonCommonData(seasonCommonData);
-                    
+                    if(seasonCommonData != null)
+                    {
+                        seasonCommonData.setRemarks(request.getParameter("remarks") != null ? request.getParameter("remarks") : "");
+                        SessionControllerGetter.getAppleFruitMothBean().storeObservationSitePointSeasonCommonData(seasonCommonData);
+                    }
                     //System.out.println("sitePointSetLength=" + observationSite.getObservationSitePointSet().size());
                     treeNames.stream().forEach(treeName->{
                         try {
@@ -311,6 +313,7 @@ public class AppleFruitMothController extends HttpServlet {
                             newData.setAutumnDate(autumnDate);
                             newData.setSpringValue(springValue);
                             newData.setSpringDate(springDate);
+                            newData.setLastUpdated(new Date());
                             
                             SessionControllerGetter.getAppleFruitMothBean().storeObservationSitePointSeasonData(newData);
                             //dataSet.add(newData);
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java
index 716bd8a3e8ad935fab205a6e72c86f355b10b8e5..bf96fa03642907de80bd4e7c0b8caef084f8b059 100755
--- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java
@@ -21,6 +21,7 @@ package no.nibio.vips.logic.modules.applefruitmoth;
 
 import com.vividsolutions.jts.geom.Geometry;
 import java.io.Serializable;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.Set;
 import javax.persistence.Basic;
@@ -78,6 +79,8 @@ public class ObservationSite implements Serializable, Comparable {
     @JoinColumn(name = "gis_id", referencedColumnName="gis_id")
     @OneToOne
     private Gis gisId;
+    @Transient
+    private Date lastUpdatedClusterCount;
 
 
     public ObservationSite() {
@@ -184,4 +187,18 @@ public class ObservationSite implements Serializable, Comparable {
     public void setGisId(Gis gisId) {
         this.gisId = gisId;
     }
+
+    /**
+     * @return the lastUpdatedClusterCount
+     */
+    public Date getLastUpdatedClusterCount() {
+        return lastUpdatedClusterCount;
+    }
+
+    /**
+     * @param lastUpdatedClusterCount the lastUpdatedClusterCount to set
+     */
+    public void setLastUpdatedClusterCount(Date lastUpdatedClusterCount) {
+        this.lastUpdatedClusterCount = lastUpdatedClusterCount;
+    }
 }
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java
index f45d325c969924f9220ef071324ffa32e27297a0..7dc105836277ec94e71dd6801e0d76cf3249e011 100755
--- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java
@@ -67,6 +67,9 @@ public class ObservationSitePointSeasonData implements Serializable {
     @JoinColumn(name = "observation_site_point_id", referencedColumnName = "observation_site_point_id", insertable = false, updatable = false)
     @ManyToOne(optional = false)
     private ObservationSitePoint observationSitePoint;
+    @Column(name = "last_updated")
+    @Temporal(TemporalType.DATE)
+    private Date lastUpdated;
 
     public ObservationSitePointSeasonData() {
     }
@@ -152,4 +155,18 @@ public class ObservationSitePointSeasonData implements Serializable {
         return "no.nibio.vips.logic.modules.applefruitmoth.ObservationSitePointSeasonData[ observationSitePointSeasonDataPK=" + observationSitePointSeasonDataPK + " ]";
     }
 
+    /**
+     * @return the lastUpdated
+     */
+    public Date getLastUpdated() {
+        return lastUpdated;
+    }
+
+    /**
+     * @param lastUpdated the lastUpdated to set
+     */
+    public void setLastUpdated(Date lastUpdated) {
+        this.lastUpdated = lastUpdated;
+    }
+
 }
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java
index 27842f454f9411a4a4d509667ab30aa9cdc10fdd..fbe051b142a539472f03319bd1f3c6529ff5cca0 100755
--- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java
@@ -30,6 +30,8 @@ import javax.persistence.ManyToOne;
 import javax.persistence.NamedQueries;
 import javax.persistence.NamedQuery;
 import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
 import javax.xml.bind.annotation.XmlRootElement;
 
 /**
@@ -59,6 +61,7 @@ public class ObservationSiteSeasonCommonData implements Serializable {
     @Column(name = "remarks")
     private String remarks;
     @Column(name = "last_updated")
+    @Temporal(TemporalType.DATE)
     private Date lastUpdated;
     @JoinColumn(name = "observation_site_id", referencedColumnName = "observation_site_id", insertable = false, updatable = false)
     @ManyToOne(optional = false)
diff --git a/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java b/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java
index cfe05d635f1d1905a2e17de9ada75aefcbefc266..c8cd224ac8b10bc85198d61f974bcf2cdd017217 100755
--- a/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java
+++ b/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java
@@ -369,6 +369,12 @@ public class RoughageService {
         Organization org = em.find(Organization.class, organizationId);
         Integer VIPSCoreUserId = org.getDefaultVipsCoreUserId();
         
+        /*System.out.println("Antall ordinære værdata: " + observations.size());
+        for(WeatherObservation obs:observations)
+        {
+            System.out.println(obs.toString());
+        }*/
+        
         List<Result> results;
         try
         {
@@ -376,6 +382,7 @@ public class RoughageService {
         }
         catch(RunModelException ex)
         {
+            //System.out.println("Feilen skjer med ordinære værdata");
             return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build();
         }
         // NORMALDATA
@@ -402,6 +409,10 @@ public class RoughageService {
                     latestObsDate
                 );
 
+                // The observations are tainted with the _NORMAL prefix, must clean up 
+                // before sending to model
+                observations.stream().forEach(obs->obs.setElementMeasurementTypeId(obs.getElementMeasurementTypeId().substring(0, obs.getElementMeasurementTypeId().indexOf("_NORMAL"))));
+                
                 // Add waterings to normal data precipitation?
                 if(
                         wateringAffectsNormalData != null && wateringAffectsNormalData.equals("true")
@@ -418,6 +429,7 @@ public class RoughageService {
                             //System.out.println("Old: " + obs.getValue() + ", new: " + (obs.getValue() + wateringMap.get(obs.getTimeMeasured())));
                             obs.setValue(obs.getValue() + wateringMap.get(obs.getTimeMeasured()));
                         }
+                        
                     }
                 }
                 /*System.out.println("Antall normaldata: " + observations.size());
diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/grid/preprocessor/ZymoseptoriaSimpleRiskGridModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/grid/preprocessor/ZymoseptoriaSimpleRiskGridModelPreprocessor.java
index 4c76b48195fe64b623248a0fc6f89e7f8fc6897d..4dd372e9dbc7864a752b36e597a0fc5e0f9aa684 100644
--- a/src/main/java/no/nibio/vips/logic/scheduling/model/grid/preprocessor/ZymoseptoriaSimpleRiskGridModelPreprocessor.java
+++ b/src/main/java/no/nibio/vips/logic/scheduling/model/grid/preprocessor/ZymoseptoriaSimpleRiskGridModelPreprocessor.java
@@ -21,6 +21,8 @@ package no.nibio.vips.logic.scheduling.model.grid.preprocessor;
 
 import com.vividsolutions.jts.geom.Coordinate;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -46,26 +48,48 @@ public class ZymoseptoriaSimpleRiskGridModelPreprocessor extends ModelRunPreproc
 
     @Override
     public ModelConfiguration getModelConfiguration(ForecastConfiguration configuration) throws PreprocessorException {
+        
         ModelConfiguration modelConfig = new ModelConfiguration();
         // Which weather stations??
         // Ilseng and Apelsvoll to start with ;-)
-        List<PointOfInterestWeatherStation> stations = Stream.of(new Integer[]{50,91,87}).map(
+        List<PointOfInterestWeatherStation> stations = Stream.of(configuration.getGridWeatherStationPointOfInterestIds()).map(
                 stationId -> (PointOfInterestWeatherStation) SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(stationId)
             ).collect(Collectors.toList());
         
         List<PointWeatherObservationList> allObs = new ArrayList<>();
-        
+        WeatherUtil wUtil = new WeatherUtil();
         for(PointOfInterestWeatherStation station:stations)
         {
             Coordinate coordinate = new Coordinate(station.getPointOfInterest().getLongitude(), station.getPointOfInterest().getLatitude());
             List<WeatherObservation> stationObs = getStationObs(station, configuration);
-            PointWeatherObservationList pointObs = new PointWeatherObservationList(coordinate, stationObs);
+            try
+            {
+                // We need TM, UM and RR. BT is optional
+                List<WeatherObservation> mandatory = wUtil.filterWeatherObservationsByParameter(stationObs, new HashSet<>(Arrays.asList("TM","UM","RR")));
+                stationObs = wUtil.checkForAndFixHourlyTimeSeriesHolesMultiParameter(mandatory, 6);
+            }
+            catch(WeatherObservationListException ex)
+            {
+                throw new PreprocessorException("Problem with station #" + station.getPointOfInterestId() + ": " + ex.getMessage());
+            }
+            // Checking for BT
+            try
+            {
+                List<WeatherObservation> BT = wUtil.filterWeatherObservationsByParameter(stationObs, new HashSet<>(Arrays.asList("BT")));
+                stationObs.addAll(wUtil.checkForAndFixHourlyTimeSeriesHoles(BT, 6));
+            }
+            catch(WeatherObservationListException ex)
+            {
+                
+            }
+            
+            PointWeatherObservationList pointObs = new PointWeatherObservationList(coordinate, stationObs, station.getTimeZone());
             allObs.add(pointObs);
         }
         
         modelConfig.setConfigParameter("multiPointWeatherObservations", allObs);
         modelConfig.setModelId(this.getModelId());
-        modelConfig.setConfigParameter("timeZone", stations.get(0).getTimeZone());
+        modelConfig.setConfigParameter("timeZone", configuration.getTimeZone());
         return modelConfig;
     }
 
diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/FinnCerealModelsPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/FinnCerealModelsPreprocessor.java
index 790d467bb0fe60f94a173561336098e7bdf480bd..d648ac9f093e615a3665ae430e2adbe418c5f032 100644
--- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/FinnCerealModelsPreprocessor.java
+++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/FinnCerealModelsPreprocessor.java
@@ -2,10 +2,7 @@ package no.nibio.vips.logic.scheduling.model.preprocessor;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Date;
-import java.util.HashSet;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -15,7 +12,6 @@ import no.nibio.vips.logic.entity.ForecastConfiguration;
 import no.nibio.vips.logic.entity.PointOfInterestWeatherStation;
 import no.nibio.vips.logic.scheduling.model.ModelRunPreprocessor;
 import no.nibio.vips.logic.scheduling.model.PreprocessorException;
-import no.nibio.vips.model.ConfigValidationException;
 import no.nibio.vips.util.WeatherElements;
 import no.nibio.vips.util.WeatherObservationListException;
 import no.nibio.vips.util.WeatherUtil;
diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java
index 70d882c833888b18315e44019826620fa2855104..1a057da43767ec296470e3242448b463fbd2fd2e 100755
--- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java
+++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java
@@ -115,20 +115,25 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{
                                             ex.getMessage(), 
                                             SchedulingUtil.MESSAGE_STATUS_DANGER)
                                     );
-                            //System.out.println("Error caught");
-                            continue;
+                            //System.out.println("###########################   Error caught: " + errorMessage);
+                            //System.out.println("numberOfCompletedForecastConfigurations=" + numberOfCompletedForecastConfigurations);
+                            //System.out.println("totalNumberofForecastConfigurations=" + totalNumberofForecastConfigurations);
+                            //continue;
                         }
 
                     }
                     if(totalNumberofForecastConfigurations > 0)
                     {
+                        noForecastConfigurationsFound = false;
                         double completeness = (double) numberOfCompletedForecastConfigurations/totalNumberofForecastConfigurations;
                         tec.setCompleteness(completeness);
                     }
                     else
                     {
                         noForecastConfigurationsFound = true;
+                        //System.out.println("noForecastConfigurationsFound == true!!");
                     }
+                    //System.out.println("Current completeness=" + tec.getTaskExecutor().getCompleteness());
                 }
             }
             
@@ -138,9 +143,12 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{
                tec.setCompleteness(1.0);
                tec.setStatusMessage("No current forecast configurations were found");
         }
+        
+        //System.out.println("Total completeness=" + tec.getTaskExecutor().getCompleteness());
+        
         if(tec.getTaskExecutor().getCompleteness() != 1.0)
         {
-            //System.out.println("Error detected");
+            //System.out.println("Error detected, RuntimeException thrown just after this");
             tec.setStatusMessage(errorMessage.toString());
             throw new RuntimeException();
         }
diff --git a/src/main/java/no/nibio/vips/logic/service/LogicService.java b/src/main/java/no/nibio/vips/logic/service/LogicService.java
index 837b41de094bf1270fe5a50bcfd35fd585211f48..c3f4a7d0e3989d6b320450b6f4c2981e7a16c9b1 100755
--- a/src/main/java/no/nibio/vips/logic/service/LogicService.java
+++ b/src/main/java/no/nibio/vips/logic/service/LogicService.java
@@ -859,6 +859,14 @@ public class LogicService {
         }
     }
     
+    @GET
+    @Path("organization")
+    @Produces("application/json;charset=UTF-8")
+    public Response getOrganizations()
+    {
+        return Response.ok().entity(SessionControllerGetter.getUserBean().getOrganizations()).build();
+    }
+    
     /**
      * Get the client to use for calling VIPSCoreManager REST services programmatically
      * @return 
diff --git a/src/main/java/no/nibio/vips/logic/service/ModelFormService.java b/src/main/java/no/nibio/vips/logic/service/ModelFormService.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a00a583c3c5499536ece87dc2298010cb88c671
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/service/ModelFormService.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by 
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ * 
+ * VIPSLogic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * NIBIO Open Source License for more details.
+ * 
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic.  If not, see <http://www.nibio.no/licenses/>.
+ * 
+ */
+
+package no.nibio.vips.logic.service;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.webcohesion.enunciate.metadata.Facet;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import no.nibio.vips.entity.ModelConfiguration;
+import no.nibio.vips.entity.Result;
+import no.nibio.vips.entity.WeatherObservation;
+import no.nibio.vips.gis.GISUtil;
+import no.nibio.vips.logic.entity.Organization;
+import no.nibio.vips.logic.entity.PointOfInterestWeatherStation;
+import no.nibio.vips.logic.entity.WeatherStationDataSource;
+import no.nibio.vips.logic.util.RunModelException;
+import no.nibio.vips.logic.util.SessionControllerGetter;
+import no.nibio.vips.logic.util.SystemTime;
+import no.nibio.vips.util.ParseRESTParamUtil;
+import no.nibio.vips.util.WeatherElements;
+import no.nibio.vips.util.WeatherUtil;
+import no.nibio.vips.util.XDate;
+import no.nibio.vips.util.weather.WeatherDataSourceException;
+import no.nibio.vips.util.weather.WeatherDataSourceUtil;
+
+/**
+ * This is a collection of services for models run from forms (not as part of batch) 
+ * @copyright 2018 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Path("rest/modelform")
+@Facet("restricted")
+public class ModelFormService {
+
+    @GET
+    @Path("SEPTORIAHU/runmodel")
+    @Produces("application/json;charset=UTF-8")
+    public Response runSeptoriaHumidityModel(
+            @QueryParam("organizationId_countryCode") String organizationId_countryCode,
+            @QueryParam("weatherStationId") String weatherStationId, // Could be special ID from Danish system,
+            @QueryParam("dateSpraying1") String dateSpraying1,
+            @QueryParam("dateSpraying2") String dateSpraying2,
+            @QueryParam("dateGs31") String dateGs31,
+            @QueryParam("date3rdUpperLeafEmerging") String date3rdUpperLeafEmerging,
+            @QueryParam("date2ndUpperLeafEmerging") String date2ndUpperLeafEmerging,
+            @QueryParam("dateUpperLeafEmerging") String dateUpperLeafEmerging,
+            @QueryParam("dateGs75") String dateGs75,
+            @QueryParam("thresholdRelativeHumidity") Double thresholdRelativeHumidity,
+            @QueryParam("thresholdLeafWetness") Double thresholdLeafWetness,
+            @QueryParam("thresholdPrecipitation") Double thresholdPrecipitation,
+            @QueryParam("slidingHoursPast") Integer slidingHoursPast,
+            @QueryParam("slidingHoursAhead") Integer slidingHoursAhead,
+            @QueryParam("thresholdHumidPeriodHours") Integer thresholdHumidPeriodHours,
+            @QueryParam("sprayingProtectionDays") Integer sprayingProtectionDays,
+            @QueryParam("leafLifeTime") Integer leafLifeTime
+    ){
+        try
+        {
+            ModelConfiguration mConf = new ModelConfiguration();
+            mConf.setModelId("SEPTORIAHU");
+            mConf.setConfigParameter("dateSpraying1", dateSpraying1);
+            mConf.setConfigParameter("dateSpraying2", dateSpraying2);
+            mConf.setConfigParameter("dateGs31", dateGs31);
+            mConf.setConfigParameter("date3rdUpperLeafEmerging", date3rdUpperLeafEmerging);
+            mConf.setConfigParameter("date2ndUpperLeafEmerging", date2ndUpperLeafEmerging);
+            mConf.setConfigParameter("dateUpperLeafEmerging", dateUpperLeafEmerging);
+            mConf.setConfigParameter("dateGs75", dateGs75);
+            mConf.setConfigParameter("thresholdRelativeHumidity", thresholdRelativeHumidity);
+            mConf.setConfigParameter("thresholdLeafWetness", thresholdLeafWetness);
+            mConf.setConfigParameter("thresholdPrecipitation", thresholdPrecipitation);
+            mConf.setConfigParameter("slidingHoursPast", slidingHoursPast);
+            mConf.setConfigParameter("slidingHoursAhead", slidingHoursAhead);
+            mConf.setConfigParameter("thresholdHumidPeriodHours", thresholdHumidPeriodHours);
+            mConf.setConfigParameter("sprayingProtectionDays", sprayingProtectionDays);
+            mConf.setConfigParameter("leafLifeTime", leafLifeTime);
+
+            // Data parsing
+
+            Integer organizationId = Integer.valueOf(organizationId_countryCode.split("_")[0]);
+            Organization organization = SessionControllerGetter.getUserBean().getOrganization(organizationId);
+            mConf.setConfigParameter("timeZone", organization.getDefaultTimeZone());
+            TimeZone timeZone =  TimeZone.getTimeZone(organization.getDefaultTimeZone());
+            ParseRESTParamUtil pUtil = new ParseRESTParamUtil();
+            // Start time is gs31, easy
+            Date gs31 = pUtil.parseISODate(dateGs31,timeZone);
+            XDate startTime = new XDate(gs31);
+            startTime.addDays(-1);
+            // End time is whatever comes first of the day after tomorrow or Gs75
+            Date gs75 = pUtil.parseISODate(dateGs75, timeZone);
+            XDate dayAfterTomorrow = new XDate(SystemTime.getSystemTime());
+            dayAfterTomorrow.addDays(2);
+            WeatherUtil wUtil = new WeatherUtil();
+            dayAfterTomorrow = new XDate(wUtil.pragmaticAdjustmentToMidnight(dayAfterTomorrow, timeZone));
+            // The first check here is to see if the systemtime is too early
+            Date endTime = dayAfterTomorrow.after(gs75) ? gs75 : dayAfterTomorrow;
+
+            String countryCode = organizationId_countryCode.split("_")[1];
+            List<WeatherObservation> observations;
+            WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil();
+            PointOfInterestWeatherStation ws;
+            if(countryCode.toLowerCase().equals("dk")){
+                // Create a synthetic weather station to pass into the system
+                // Weather station id is a UTM32N coordinate, e.g. E552700N6322400
+                String[] parts = weatherStationId.split("N");
+                Integer UTM32vE = Integer.valueOf(parts[0].substring(1));
+                Integer UTM32vN = Integer.valueOf(parts[1]);
+                GISUtil gisUtil = new GISUtil();
+                Coordinate UTMc = new Coordinate(UTM32vE, UTM32vN); 
+                Coordinate coordinate = gisUtil.convertCoordinate(UTMc, "EPSG:32632", "EPSG:4326");
+                WeatherStationDataSource wsds = SessionControllerGetter.getPointOfInterestBean().getWeatherStationDataSource("DMI PointWeb");
+                ws = new PointOfInterestWeatherStation();
+                ws.setWeatherStationDataSourceId(wsds);
+                ws.setWeatherStationRemoteId(coordinate.y + "," + coordinate.x);// For some reason, The transformation switches X/Y
+                ws.setTimeZone(organization.getDefaultTimeZone());
+                
+                //observations.stream().forEach(obs->System.out.println(obs.toString()));
+            }
+            else
+            {
+                // Weather station id maps to a regular weather station
+                ws = (PointOfInterestWeatherStation) SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(Integer.valueOf(weatherStationId));
+            }
+            observations = wdsUtil.getWeatherObservations(
+                        ws, 
+                        WeatherObservation.LOG_INTERVAL_ID_1H, 
+                        new String[]{
+                            WeatherElements.TEMPERATURE_MEAN,
+                            WeatherElements.PRECIPITATION,
+                            WeatherElements.RELATIVE_HUMIDITY_MEAN,
+                            WeatherElements.LEAF_WETNESS
+                        }, 
+                        startTime, 
+                        endTime
+                );
+            mConf.setConfigParameter("observations",observations);
+
+            Integer VIPSCoreUserId = organization.getDefaultVipsCoreUserId();
+
+            List<Result>results = SessionControllerGetter.getForecastBean().runForecast(mConf, VIPSCoreUserId);
+
+            return Response.ok().entity(results).build();
+        }
+        catch(WeatherDataSourceException | RunModelException ex)
+        {
+            return Response.serverError().entity(ex.getMessage()).build();
+        }
+    }
+}
diff --git a/src/main/java/no/nibio/vips/logic/service/WeatherProxyService.java b/src/main/java/no/nibio/vips/logic/service/WeatherProxyService.java
index 842641bc29029c226f571007d988250cf022bb55..4f91248f398f8998233260616d2f2e6f25260ed3 100755
--- a/src/main/java/no/nibio/vips/logic/service/WeatherProxyService.java
+++ b/src/main/java/no/nibio/vips/logic/service/WeatherProxyService.java
@@ -23,7 +23,9 @@ import com.vividsolutions.jts.geom.Envelope;
 import com.vividsolutions.jts.geom.GeometryFactory;
 import com.webcohesion.enunciate.metadata.Facet;
 import java.io.UnsupportedEncodingException;
+import java.net.URI;
 import java.net.URLDecoder;
+import java.text.MessageFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
@@ -40,9 +42,11 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
 import no.nibio.vips.entity.PointWeatherObservationList;
 import no.nibio.vips.entity.WeatherObservation;
 import no.nibio.vips.logic.util.SystemTime;
+import no.nibio.vips.util.XDate;
 import no.nibio.vips.util.weather.ALabDataParser;
 import no.nibio.vips.util.weather.FruitWebDavisDataParser;
 import no.nibio.vips.util.weather.MetosAPIDataParser;
@@ -90,6 +94,41 @@ public class WeatherProxyService {
         return Response.ok().entity(observations).build();
     }
     
+    @GET
+    @POST
+    @Path("fmi/{stationId}")
+    @GZIP
+    @Produces("application/json;charset=UTF-8")
+    public Response getMetosRIMProWeatherData(
+            @PathParam("stationId") String stationId, 
+            @FormParam("timeZone") String timeZonePOST, 
+            @QueryParam("timeZone") String timeZoneGET, 
+            @FormParam("startDate") String startDatePOST,
+            @QueryParam("startDate") String startDateGET,
+            @FormParam("endDate") String endDatePOST,
+            @QueryParam("endDate") String endDateGET
+            )
+    {
+        String FMI_URL_TEMPLATE="http://www.cropinfra.com:8080/weather/resources/fmi/temporal/vips/{0}/{1}/{2}";
+        List<WeatherObservation> observations;
+        try 
+        {
+            String timeZoneParam = timeZonePOST != null ? timeZonePOST : timeZoneGET != null ? timeZoneGET : "UTC";
+            TimeZone timeZone = TimeZone.getTimeZone(timeZoneParam);
+            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+            format.setTimeZone(timeZone);
+            String startDateParam = startDatePOST != null ? startDatePOST : startDateGET;
+            XDate startDate1 = new XDate(format.parse(startDateParam));
+            String endDateParam = endDatePOST != null ? endDatePOST : endDateGET;
+            XDate endDate1 = new XDate(format.parse(endDateParam));
+            URI uri = UriBuilder.fromUri(MessageFormat.format(FMI_URL_TEMPLATE, stationId, startDate1.getISOUTCFormat(), endDate1.getISOUTCFormat())).build();
+            //observations = new MetosRIMProDataParser().getWeatherObservations(stationId, timeZone, startDate1);
+            return Response.temporaryRedirect(uri).build();
+        } catch (ParseException | NullPointerException ex) {
+            return Response.serverError().entity(ex).build();
+        }
+    }
+    
     @GET
     @POST
     @Path("metosapi/{stationId}")
diff --git a/src/main/java/no/nibio/vips/logic/util/Globals.java b/src/main/java/no/nibio/vips/logic/util/Globals.java
index 4874cf7f0983eee6228d569bcf86eea3cb55c75a..1f12188e6379392d360feade1dc8fbfdc12ce2f3 100755
--- a/src/main/java/no/nibio/vips/logic/util/Globals.java
+++ b/src/main/java/no/nibio/vips/logic/util/Globals.java
@@ -70,6 +70,7 @@ public class Globals {
     public static String[] availableTimeZones = {
         "UTC",
         "Etc/GMT-1",
+        "Europe/Copenhagen",
         "Europe/Oslo",
         "Europe/Sarajevo",
         "Europe/Stockholm",
diff --git a/src/main/java/no/nibio/vips/util/weather/MetosAPIDataParser.java b/src/main/java/no/nibio/vips/util/weather/MetosAPIDataParser.java
index 322d28cfe59ebf42db0bed1c17af6220d9555c2e..e42cc6568e46a7d1c2ec5289d7ef7eb58e19c6a3 100644
--- a/src/main/java/no/nibio/vips/util/weather/MetosAPIDataParser.java
+++ b/src/main/java/no/nibio/vips/util/weather/MetosAPIDataParser.java
@@ -230,7 +230,7 @@ public class MetosAPIDataParser {
         try
         {
             String accessToken = this.getToken();
-            HttpGet httpget = new HttpGet("https://api.fieldclimate.com/v1/data/optimized/000024A0/hourly/from/" + (startDate.getTime() / 1000)); 
+            HttpGet httpget = new HttpGet("https://api.fieldclimate.com/v1/data/optimized/" + stationId + "/hourly/from/" + (startDate.getTime() / 1000)); 
 
             httpget.addHeader("Accept", "application/json");
             httpget.addHeader("Authorization", "Bearer " + accessToken);
diff --git a/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java b/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java
index 3e94f1becf4cb2ed3391df2cce4e124fd890433f..e79b30a8169d8e02191051c01225b65059a437fc 100755
--- a/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java
+++ b/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java
@@ -189,6 +189,7 @@ public class WeatherDataSourceUtil {
             URLOutput = IOUtils.toString(URLStream);
             List<WeatherObservation> preliminaryResult = this.getWeatherObservations(URLOutput);
             List<WeatherObservation> filteredObservations = new ArrayList<>();
+            //System.out.println(this.getClass().getName() + "/preliminaryResult.size()=" + preliminaryResult.size());
             preliminaryResult.stream().filter((candidateObs) -> (
                     candidateObs.getLogIntervalId().equals(logIntervalId)
                     && Arrays.asList(elementMeasurementTypes).contains(candidateObs.getElementMeasurementTypeId())
@@ -196,6 +197,7 @@ public class WeatherDataSourceUtil {
                 ).forEachOrdered((candidateObs) -> {
                     filteredObservations.add(candidateObs);
                 });
+            //System.out.println(this.getClass().getName() + "/filteredObservations.size()=" + filteredObservations.size());
             return filteredObservations;
         } catch (IOException ex) {
             StringBuilder errorMessage = new StringBuilder().append("Could not fetch weather observations from URI ").append(URL.toString()).append(".\n");
diff --git a/src/main/java/no/nibio/vips/util/weather/dnmipointweb/DMIPointWebDataParser.java b/src/main/java/no/nibio/vips/util/weather/dnmipointweb/DMIPointWebDataParser.java
index cf704d3132e63304eab0fa11118495f0687cd23d..36e7a08a24101257e25d55fb2a8eb191e56d28b8 100644
--- a/src/main/java/no/nibio/vips/util/weather/dnmipointweb/DMIPointWebDataParser.java
+++ b/src/main/java/no/nibio/vips/util/weather/dnmipointweb/DMIPointWebDataParser.java
@@ -19,7 +19,10 @@
 
 package no.nibio.vips.util.weather.dnmipointweb;
 
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
@@ -55,15 +58,16 @@ public class DMIPointWebDataParser {
     
     public List<WeatherObservation> getData(Double longitude, Double latitude, Date dateFrom, Date dateTo)
     {
-        List<WeatherObservation> retVal = new ArrayList<>();
+        List<WeatherObservation> allObservations = new ArrayList<>();
+        TimeZone danishTZ = TimeZone.getTimeZone("Europe/Copenhagen");
         try {
             IWeatherService proxy = new WeatherService().getSslOffloadedBasicHttpBindingIWeatherService();
             UseableArrayOfWeatherDataSource wdsource = new UseableArrayOfWeatherDataSource();
             wdsource.add(WeatherDataSource.OBS);
             wdsource.add(WeatherDataSource.FORECAST);
-            wdsource.add(WeatherDataSource.NORMAL);
-
-            GregorianCalendar gc = new GregorianCalendar(TimeZone.getTimeZone("Europe/Copenhagen"));
+            //wdsource.add(WeatherDataSource.NORMAL);
+            
+            GregorianCalendar gc = new GregorianCalendar(danishTZ);
             gc.setTime(dateFrom);
             XMLGregorianCalendar calFrom = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
             XMLGregorianCalendar calTo = null;
@@ -79,7 +83,8 @@ public class DMIPointWebDataParser {
                     listedParam -> wdparam.add(listedParam)
             );
             
-            WeatherResponse result = proxy.getWeatherData(
+            //WeatherResponse result = proxy.getWeatherData(
+            WeatherResponse result = proxy.getWeatherDataExtended(
                 String.valueOf(latitude).replace(".", ","), // Latitude ("X") Decimal separator is comma!
                 String.valueOf(longitude).replace(".", ","), // Longitude ("Y") Decimal separator is comma!
                 false, // true if UTM, false if decimal degrees
@@ -90,18 +95,19 @@ public class DMIPointWebDataParser {
                 calTo, // End of period with data
                 wdparam, // Set of requested parameters
                 0.0, // Base temperature value
-                false // Use base temperature? (t/f)
+                false, // Use base temperature? (t/f)
+                true // Get 6 days of forecasts (only for the proxy.getWeatherDataExtended method)
             );
-             
             
-
             ArrayOfWeatherDataModel value = result.getWeahterDataList().getValue();
             value.getWeatherDataModel().stream().forEach(weatherDataModel -> {
                     DMIPointWebDataParser.PARAM_MAP.keySet().stream().forEach(
                             VIPSParam->{
                                 WeatherObservation obs = this.getWeatherObservation(VIPSParam, weatherDataModel);
                                 if(obs != null)
-                                    retVal.add(obs);
+                                {
+                                    allObservations.add(obs);
+                                }
                             }
                     );
                 }
@@ -110,8 +116,24 @@ public class DMIPointWebDataParser {
         } catch (Exception ex) {
             Logger.getLogger(DMIPointWebDataParser.class.getName()).log(Level.SEVERE, null, ex);
         }
-        System.out.println("Number of extracted weather data = " + retVal.size());
-        return retVal;
+        //System.out.println("Number of extracted weather data = " + retVal.size());
+        // After "now", the DMI service provides forecast values seamlessly. After approx 48 hours these
+        // values turn into 6 hour intervals, which we can't use. We need to weed them out
+        Collections.sort(allObservations);
+        ZonedDateTime now = ZonedDateTime.now();
+        ZonedDateTime lastValidObsTime = null;
+        ZoneId danishZ = ZoneId.of("Europe/Copenhagen");
+        List<WeatherObservation> filteredObservations = new ArrayList<>();
+        for(WeatherObservation obs:allObservations)
+        {
+            ZonedDateTime obsTime = ZonedDateTime.ofInstant(obs.getTimeMeasured().toInstant(),danishZ);
+            if(lastValidObsTime == null || obsTime.isBefore(now) || obsTime.minusHours(6).isBefore(lastValidObsTime))
+            {
+                filteredObservations.add(obs);
+                lastValidObsTime = obsTime;
+            }            
+        }
+        return allObservations;
     }
 
     private WeatherObservation getWeatherObservation(String VIPSParam, WeatherDataModel wDataModel) {
diff --git a/src/main/java/no/nibio/vips/util/weather/metnothredds/MetNoThreddsDataParser.java b/src/main/java/no/nibio/vips/util/weather/metnothredds/MetNoThreddsDataParser.java
index 5688971da1930b031e0c9d4141431d6be5c3b142..852901e3c9bc4a60c9df9178f4b4534e6f492253 100644
--- a/src/main/java/no/nibio/vips/util/weather/metnothredds/MetNoThreddsDataParser.java
+++ b/src/main/java/no/nibio/vips/util/weather/metnothredds/MetNoThreddsDataParser.java
@@ -297,7 +297,7 @@ public class MetNoThreddsDataParser {
             Map<Long, WeatherObservation> hashedObsForPoint = tempRetVal.get(c);
             List<WeatherObservation> obsList = new ArrayList(hashedObsForPoint.values());
             Collections.sort(obsList);
-            PointWeatherObservationList obsForPoint = new PointWeatherObservationList(c,obsList);
+            PointWeatherObservationList obsForPoint = new PointWeatherObservationList(c,obsList,"UTC");
             retVal.add(obsForPoint);
         }
         return retVal;
diff --git a/src/main/java/no/nibio/web/forms/FormField.java b/src/main/java/no/nibio/web/forms/FormField.java
index 4da5599561df0955b2fefb9c9c47adabd4926f1c..65e23918e16b8888104ca29dfe69439ca0273245 100755
--- a/src/main/java/no/nibio/web/forms/FormField.java
+++ b/src/main/java/no/nibio/web/forms/FormField.java
@@ -20,6 +20,7 @@
 package no.nibio.web.forms;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.GeometryFactory;
 import com.vividsolutions.jts.geom.Point;
@@ -42,6 +43,7 @@ import java.util.TimeZone;
  * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a>
  * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
  */
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class FormField {
     public final static String DATA_TYPE_STRING = "STRING";
     public final static String DATA_TYPE_INTEGER = "INTEGER";
diff --git a/src/main/java/no/nibio/web/forms/FormSelectOption.java b/src/main/java/no/nibio/web/forms/FormSelectOption.java
index 9f510e37a1c867c7ed60d728575e6b2e6468a4ec..941ae5a03473b68ca6dcc33d071c0d67655e40eb 100755
--- a/src/main/java/no/nibio/web/forms/FormSelectOption.java
+++ b/src/main/java/no/nibio/web/forms/FormSelectOption.java
@@ -19,6 +19,8 @@
 
 package no.nibio.web.forms;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
 /**
  * Represents an option in a select field
  * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a>
diff --git a/src/main/resources/db/migration/V3__ForecastConfig_Gridstations.sql b/src/main/resources/db/migration/V3__ForecastConfig_Gridstations.sql
new file mode 100644
index 0000000000000000000000000000000000000000..e994d1f290a7f7268b617663dc7c158f57680882
--- /dev/null
+++ b/src/main/resources/db/migration/V3__ForecastConfig_Gridstations.sql
@@ -0,0 +1,25 @@
+/* 
+ * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. 
+ * 
+ * This file is part of VIPSLogic.
+ * VIPSLogic is free software: you can redistribute it and/or modify
+ * it under the terms of the NIBIO Open Source License as published by 
+ * NIBIO, either version 1 of the License, or (at your option) any
+ * later version.
+ * 
+ * VIPSLogic is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * NIBIO Open Source License for more details.
+ * 
+ * You should have received a copy of the NIBIO Open Source License
+ * along with VIPSLogic.  If not, see <http://www.nibio.no/licenses/>.
+ * 
+ */
+/**
+ * Author:  Tor-Einar Skog
+ * Created: May 2, 2018
+ */
+
+ALTER TABLE forecast_configuration
+ADD COLUMN grid_weather_station_point_of_interest_ids INTEGER[];
\ No newline at end of file
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
index 26eae52a23c2dba8934029232f8cbcc11063bdbd..cb32a49a824de62c28fa4a1f29bbd6818d5f90e9 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -453,3 +453,7 @@ vipsLogicRole_8=Apple Fruit Moth Rowanberry Cluster Counter
 pointOfInterestType_4=Region
 task_RunGridModelsTask_name=Run grid models
 task_RunGridModelsTask_description=Run models that cover several locations
+currentDate=Current date
+days=Days
+older=Older
+lastUpdated=Last updated
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
index 3af974595514b02ea7cd37927c89cd475d0c7b9b..aa1bb34b1129629b176339e1cfa2e986517f49b2 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
@@ -453,3 +453,7 @@ vipsLogicRole_8=Apple Fruit Moth Rowanberry Cluster Counter
 pointOfInterestType_4=Region
 task_RunGridModelsTask_name=Run grid models
 task_RunGridModelsTask_description=Test
+currentDate=Current date
+days=Days
+older=Older
+lastUpdated=Last updated
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
index eaa5d435a8bd68ce9d57cf4006fd7afef59fe9ec..abd9465f410c934e078d8958bc4851f3021a5aad 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
@@ -452,3 +452,7 @@ vipsLogicRole_8=Apple Fruit Moth Rowanberry Cluster Counter
 pointOfInterestType_4=Region
 task_RunGridModelsTask_name=Run grid models
 task_RunGridModelsTask_description=Test
+currentDate=Current date
+days=Days
+older=Older
+lastUpdated=Last updated
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
index 2a899f2b96badcbdff19f96b2ead9933873ecb4f..a74b126a962e160a85b3f8feb1cc648f9462cb1e 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
@@ -453,3 +453,7 @@ vipsLogicRole_8=Rogneb\u00e6rm\u00f8llklaseteller
 pointOfInterestType_4=Region
 task_RunGridModelsTask_name=Kj\u00f8r GRID-baserte modeller
 task_RunGridModelsTask_description=Kj\u00f8r modeller som spenner over flere lokaliteter 
+currentDate=Gjeldende dato
+days=Dager
+older=Eldre
+lastUpdated=Sist oppdatert
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
index f722af4d1a0f29ef27d2142d7ddd68117206cc13..1565845e361f6a34262336a3aa6452659fe69c9b 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
@@ -453,3 +453,7 @@ vipsLogicRole_8=Apple Fruit Moth Rowanberry Cluster Counter
 pointOfInterestType_4=Region
 task_RunGridModelsTask_name=Run grid models
 task_RunGridModelsTask_description=Test
+currentDate=Current date
+days=Days
+older=Older
+lastUpdated=Last updated
diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
index 979001d6760254038ceed8c5326ee8f551dc8519..b275b893ee4e90de28867535ca644cba7afdbfc7 100755
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties
@@ -450,3 +450,7 @@ vipsLogicRole_8=Apple Fruit Moth Rowanberry Cluster Counter
 pointOfInterestType_4=Region
 task_RunGridModelsTask_name=Run grid models
 task_RunGridModelsTask_description=Test
+currentDate=Current date
+days=Days
+older=Older
+lastUpdated=Last updated
diff --git a/src/main/webapp/formdefinitions/appleFruitMothStationForm.json b/src/main/webapp/formdefinitions/appleFruitMothStationForm.json
index 2954c06b241566e7a6310b864a1780916b8c9226..e5e22d4611d28cf3d0df5684ebab85444a6618b5 100755
--- a/src/main/webapp/formdefinitions/appleFruitMothStationForm.json
+++ b/src/main/webapp/formdefinitions/appleFruitMothStationForm.json
@@ -1,6 +1,6 @@
 {
     "_licenseNote": [
-        "Copyright (c) 2014-2015 NIBIO <http://www.nibio.no/>. ",
+        "Copyright (c) 2014-2018 NIBIO <http://www.nibio.no/>. ",
         "",
         "This file is part of VIPSLogic. ",
         "VIPSLogic is free software: you can redistribute it and/or modify ",
@@ -16,7 +16,7 @@
         "You should have received a copy of the NIBIO Open Source License ",
         "along with VIPSLogic.  If not, see <http://www.nibio.no/licenses/>. "
     ],
-    "_comment" : "Structure of the weatherStationForm and how to validate it",
+    "_comment" : "Structure of the appleFruitMothStationForm and how to validate it",
     "fields": [
         {
             "name" : "observationSiteId",
diff --git a/src/main/webapp/formdefinitions/models/FINNCEREAL.json b/src/main/webapp/formdefinitions/models/FINNCEREAL.json
index 93aec56a3cb138f3f034e49b48f2122a29c92778..979a52b430d35d31a80211d9f4ba021a19c399e8 100644
--- a/src/main/webapp/formdefinitions/models/FINNCEREAL.json
+++ b/src/main/webapp/formdefinitions/models/FINNCEREAL.json
@@ -1,77 +1,77 @@
-{
-    "_licensenbte": [
-        "Copyright (c) 2014 NIBIO <http://www.nibio.nb/>. ",
-        "",
-        "This file is part of VIPSLogic. ",
-        "VIPSLogic is free software: you can redistribute it and/or modify ",
-        "it under the terms of the NIBIO Open Source License as published by ",
-        "NIBIO, either version 1 of the License, or (at your option) any ",
-        "later version. ",
-        "",
-        "VIPSLogic is distributed in the hope that it will be useful, ",
-        "but WITHOUT ANY WARRANTY; without even the implied warranty of ",
-        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the ",
-        "NIBIO Open Source License for more details. ",
-        "",
-        "You should have received a copy of the NIBIO Open Source License ",
-        "along with VIPSLogic.  If nbt, see <http://www.nibio.nb/licenses/>. "
-    ],
-    "_comment" : "Sowing date, previous crop, tillage method, and current crop disease susceptibility for the specific field",
-    "fields": [
-         {
-            "name" : "modelName",
-            "dataType" : "STRING",
-            "fieldType" : "SELECT_SINGLE",
-            "required" : true,
-			"options": [
-				{"value":"PyrenophoraTeres", "label":{"en":"Net Blotch","nb":"?","fi":"Verkkolaikku"}, "selected":"true"},
-				{"value":"DrechsleraTriticiRepentis", "label":{"en":"Tan Spot","nb":"","fi":"Ruskolaikku"}},
-				{"value":"StagonosporaNodorum", "label":{"en" : "Stagonspora spot", "nb":"?", "fi":"Pistelaikku"}}
-			]
-        },
-        {
-            "name" : "fieldSowingDate",
-            "dataType" : "DATE",
-            "dateFormat" : "yyyy-MM-dd",
-            "required" : true
-        },
-        {
-            "name" : "previousCrop",
-            "dataType" : "STRING",
-            "fieldType" : "SELECT_SINGLE",
-            "required" : true,
-			"options": [
-				{"value":"Wheat", "label":{"en":"Wheat","nb":"Hvete","fi":"Vehn"}, "selected":"true"},
-				{"value":"Barley", "label":{"en":"Barley","nb":"Barley","fi":"Kaura"}},
-				{"value":"Oat", "label":{"en" : "Oats", "nb":"?", "fi":"Ohra"}},
-				{"value":"Grass", "label":{"en" : "Grass", "nb":"?","fi":"Hein"}},
-				{"value":"Rapeseed", "label":{"en" : "Turnip rape", "nb":"?","fi":"Rypsi"}},
-				{"value":"SugarBeet", "label":{"en" : "Sugar beet", "nb":"?","fi":"Sokerijuurikas"}},
-				{"value":"Pulse", "label":{"en" : "Legumes", "nb":"?","fi":"Herneet"}}
-			]
-        },
-        {
-            "name" : "tillageMethod",
-            "dataType" : "STRING",
-            "fieldType" : "SELECT_SINGLE",
-            "required" : true,
-			"options": [
-				{"value":"Intensive", "label":{"en":"Ploughing","nb":"?","fi":"Kynt"}, "selected":"true"},
-				{"value":"Reduced", "label":{"en":"Reduced tillage","nb":"?","fi":"Kevytmuokkaus"}},
-				{"value":"None", "label":{"en" : "Direct seeding", "nb":"?","fi":"Suorakylv"}}
-			]
-        },
-        {
-            "name" : "cropSusceptibility",
-            "dataType" : "STRING",
-            "fieldType" : "SELECT_SINGLE",
-            "required" : true,
-			"options": [
-				{"value":"Normal", "label":{"en":"Normal","nb":"?", "fi":"normaali"}, "selected":"true"},
-				{"value":"Resistant", "label":{"en":"Resistant","nb":"?","fi":"Resistentti"}},
-				{"value":"Sensitive", "label":{"en" : "Susceptible", "nb":"?", "fi":"Haavoittuva"}}
-			]
-        }
-                
-    ]
+{
+    "_licensenote": [
+        "Copyright (c) 2018 NIBIO <http://www.nibio.nb/>. ",
+        "",
+        "This file is part of VIPSLogic. ",
+        "VIPSLogic is free software: you can redistribute it and/or modify ",
+        "it under the terms of the NIBIO Open Source License as published by ",
+        "NIBIO, either version 1 of the License, or (at your option) any ",
+        "later version. ",
+        "",
+        "VIPSLogic is distributed in the hope that it will be useful, ",
+        "but WITHOUT ANY WARRANTY; without even the implied warranty of ",
+        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the ",
+        "NIBIO Open Source License for more details. ",
+        "",
+        "You should have received a copy of the NIBIO Open Source License ",
+        "along with VIPSLogic.  If not, see <http://www.nibio.nb/licenses/>. "
+    ],
+    "_comment" : "Sowing date, previous crop, tillage method, and current crop disease susceptibility for the specific field",
+    "fields": [
+         {
+            "name" : "modelName",
+            "dataType" : "STRING",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true,
+			"selectOptions": [
+				{"value":"PyrenophoraTeres", "label":{"en":"Net Blotch","nb":"Bladflekk","fi":"Verkkolaikku"}, "selected":"true"},
+				{"value":"DrechsleraTriticiRepentis", "label":{"en":"Tan Spot","nb":"Tan Spot","fi":"Ruskolaikku"}},
+				{"value":"StagonosporaNodorum", "label":{"en" : "Stagonspora spot", "nb":"Stagonspora spot", "fi":"Pistelaikku"}}
+			]
+        },
+        {
+            "name" : "fieldSowingDate",
+            "dataType" : "DATE",
+            "dateFormat" : "yyyy-MM-dd",
+            "required" : true
+        },
+        {
+            "name" : "previousCrop",
+            "dataType" : "STRING",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true,
+			"selectOptions": [
+				{"value":"Wheat", "label":{"en":"Wheat","nb":"Hvete","fi":"Vehnä"}, "selected":"true"},
+				{"value":"Barley", "label":{"en":"Barley","nb":"Barley","fi":"Kaura"}},
+				{"value":"Oats", "label":{"en" : "Oats", "nb":"Havre", "fi":"Ohra"}},
+				{"value":"Grass", "label":{"en" : "Grass", "nb":"Gras","fi":"Heinä"}},
+				{"value":"Rapeseed", "label":{"en" : "Turnip rape", "nb":"Raps","fi":"Rypsi"}},
+				{"value":"SugarBeet", "label":{"en" : "Sugar beet", "nb":"Bete","fi":"Sokerijuurikas"}},
+				{"value":"Legumes", "label":{"en" : "Legumes", "nb":"Belgfrukter","fi":"Herneet"}}
+			]
+        },
+        {
+            "name" : "tillageMethod",
+            "dataType" : "STRING",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true,
+			"selectOptions": [
+				{"value":"Intensive", "label":{"en":"Ploughing","nb":"Pløying","fi":"Kyntö"}, "selected":"true"},
+				{"value":"Reduced", "label":{"en":"Reduced tillage","nb":"Redusert pløying","fi":"Kevytmuokkaus"}},
+				{"value":"None", "label":{"en" : "Direct seeding", "nb":"Direktesåing","fi":"Suorakylvö"}}
+			]
+        },
+        {
+            "name" : "cropSusceptibility",
+            "dataType" : "STRING",
+            "fieldType" : "SELECT_SINGLE",
+            "required" : true,
+			"selectOptions": [
+				{"value":"Normal", "label":{"en":"Normal","nb":"Normal", "fi":"normaali"}, "selected":"true"},
+				{"value":"Resistant", "label":{"en":"Resistant","nb":"Resistent","fi":"Resistentti"}},
+				{"value":"Sensitive", "label":{"en" : "Susceptible", "nb":"Sårbar", "fi":"Haavoittuva"}}
+			]
+        }
+                
+    ] 
 }
\ No newline at end of file
diff --git a/src/main/webapp/formdefinitions/models/NAERSTADMO.json b/src/main/webapp/formdefinitions/models/NAERSTADMO.json
index 448b0f6e489f3a1a8ec523e8a04073efaa56a6e4..ed54bdb5c5fafe1a3d9fa0f7f8080b422c531449 100755
--- a/src/main/webapp/formdefinitions/models/NAERSTADMO.json
+++ b/src/main/webapp/formdefinitions/models/NAERSTADMO.json
@@ -17,5 +17,5 @@
         "along with VIPSLogic.  If not, see <http://www.nibio.no/licenses/>. "
     ],
     "_comment" : "Structure of the specific fields for NAERSTADMO",
-    "fields": []
+     "fields": []
 }
\ No newline at end of file
diff --git a/src/main/webapp/js/appleFruitMothObservationSitesMap.js b/src/main/webapp/js/appleFruitMothObservationSitesMap.js
index ce67f1497ba504fbfb4e6d385c8d2b1997c92460..dd2e3e5a139ba6b22bf04fa33d405b3905594850 100755
--- a/src/main/webapp/js/appleFruitMothObservationSitesMap.js
+++ b/src/main/webapp/js/appleFruitMothObservationSitesMap.js
@@ -83,7 +83,7 @@ var initMap = function(container, mapAttribution)
 	          		trigger: 'manual',
 	          		html: true,
 	          		placement: "auto top",
-	          		title: "<a href='/applefruitmoth?action=viewObservationSite&observationSiteId=" + feature.getId() + "'>" + feature.get("name") + "</a>",
+	          		title: "<a href='/applefruitmoth?action=viewObservationSite&observationSiteId=" + feature.getId() + "'>" + feature.get("siteName") + "</a>",
 	          		content: generatePopupContents(feature.get("warningStatus"), feature.get("description"))
 	          	});
 	          	
diff --git a/src/main/webapp/js/forecastConfigurationForm.js b/src/main/webapp/js/forecastConfigurationForm.js
index 6dfca064b7eaeead2c79f3edc75c5dbc6b106417..1d15d5137f2932af3ec395d261aea883c33730e1 100755
--- a/src/main/webapp/js/forecastConfigurationForm.js
+++ b/src/main/webapp/js/forecastConfigurationForm.js
@@ -120,7 +120,7 @@ function fetchModelSpecificFieldValuesCallback(fieldValues)
         //console.log(fieldValues[i].forecastModelConfigurationPK.modelConfigParameter + ": " + fieldName);
         if(theForm[fieldName] !== null && theForm[fieldName] !== undefined)
         {
-            theForm[fieldName].value=fieldValues[i].parameterValue;
+                theForm[fieldName].value=fieldValues[i].parameterValue;
         }
     }
 }
@@ -164,6 +164,12 @@ function createFieldHTML(modelId, formId, fieldDefinition)
         var inputType = getHTMLInputType(fieldDefinition.dataType);
         fieldHTML = '<input type="' + inputType + '" class="form-control" name="' + fieldDefinition.name + '" placeholder="' + getI18nMsg(fieldDefinition.name) + '" onblur="validateField(this,\'' + modelId + '\');" />';
     }
+    else if(fieldDefinition.fieldType === fieldTypes.TYPE_SELECT_SINGLE || fieldDefinition.fieldType === fieldTypes.TYPE_SELECT_MULTIPLE)
+    {
+        fieldHTML = '<select class="form-control" name="' + fieldDefinition.name + '"onblur="validateField(this,\'' + modelId + '\')" ' + (fieldDefinition.fieldType === fieldTypes.TYPE_SELECT_MULTIPLE ? ' multiple="multiple"' : '') + '>';
+        fieldHTML += getLocalizedOptionsHTML(fieldDefinition.selectOptions);
+        fieldHTML += '</select>';
+    }
 
     return [
             replaceParams(FIELD_PREFIX,[fieldDefinition.name, getI18nMsg(fieldDefinition.name)]),
@@ -205,4 +211,4 @@ function getHTMLInputType(dataType)
         default:
             return "text";
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/webapp/js/util.js b/src/main/webapp/js/util.js
index 382314a03733ac00c4f2db4f687366bccd530939..74c3f49d49d602f7e47fd1adcf4a010fb2d2bf0d 100755
--- a/src/main/webapp/js/util.js
+++ b/src/main/webapp/js/util.js
@@ -112,7 +112,7 @@ function getLocalizedOrganismName(organism, language)
 }
 
 /**
- * Depends on the value of currentLanguage and defaultLanguage in /currentLanguage.js
+ * Depends on the value of currentLanguage and defaultLanguage in /js/environment.js
  * @param cropCategory
  * @returns {String}
  */
@@ -146,6 +146,35 @@ function getLocalizedCropCategoryName(cropCategory)
 	return "Unnamed";
 }
 
+function getLocalizedOptionsHTML(optionsList) {
+    var translatedOptionsHTML = "";
+    var languages = [environment.currentLanguage, environment.defaultLanguage, "en"];
+    
+    for(var i in optionsList){
+        var option = optionsList[i];
+        var label = null;
+        var labelList = option.label;
+	for(var j in languages)
+	{
+		for(var k in labelList)
+		{
+                    if(k === languages[j])
+                    {
+                        label = labelList[k];
+                        break;
+                    }
+		}
+            if(label !== null)
+            {
+                break;
+            }
+	}
+        translatedOptionsHTML += '<option value="' + option.value + '"' + (option.selected === "true" ? ' selected="selected"' : '') + ">" + label + "</option>";
+    }
+    
+    return translatedOptionsHTML;
+}
+
 /** Ensure that we're able to handle both a unix timestamp and an ISO timestamp
  * 
  * @param {type} ambiguousValue
diff --git a/src/main/webapp/map_applications/fireblight/js/map.js b/src/main/webapp/map_applications/fireblight/js/map.js
index 45c681b5fa18dbbe73e2eccc014b3ed5a16b9d35..451244d0b1c1e5826197e8f714b6fb8b95ae8e8f 100755
--- a/src/main/webapp/map_applications/fireblight/js/map.js
+++ b/src/main/webapp/map_applications/fireblight/js/map.js
@@ -9,61 +9,8 @@ var registration = false;
 
 function initMap()
 {
-    // OpenStreetMap background layer
-    var osm = new ol.layer.Tile({
-        'title': 'OSM',
-        type: 'base',
-        visible: true,
-        source: new ol.source.OSM({
-          attributions: [
-            new ol.Attribution({
-              html: "Kartgrunnlag: Statens kartverk (<a href='//creativecommons.org/licenses/by-sa/3.0/no/' target='new'>cc-by-sa-3.0</a>)"
-            })
-          ]
-        })
-      });
     
-    // Detailed map of Norway in shades of grey
-  var topo2graatone = new ol.layer.Tile({
-    title: "Gråtone",
-    type: 'base',
-    visible: true,
-    source: new ol.source.TileWMS({
-        attributions: [
-            new ol.Attribution({
-              html: "Kartgrunnlag: Statens kartverk (<a href='//creativecommons.org/licenses/by-sa/3.0/no/' target='new'>cc-by-sa-3.0</a>)"
-            })
-          ],
-      url: "//opencache.statkart.no/gatekeeper/gk/gk.open?",
-      params: {
-        LAYERS: 'topo2graatone',
-        VERSION: '1.1.1'
-      }
-    })
-  });
-  
-  // Detailed Norway map in colours
-  var topo2 = 
-          new ol.layer.Tile({
-    title: "Farger",
-    type: 'base',
-    visible: true,
-    source: new ol.source.TileWMS({
-         attributions: [
-            new ol.Attribution({
-              html: "Kartgrunnlag: Statens kartverk (<a href='//creativecommons.org/licenses/by/4.0/deed.no' target='new'>cc-by-sa-4.0</a>)"
-            })
-          ],
-      url: "//opencache.statkart.no/gatekeeper/gk/gk.open?",
-      params: {
-        LAYERS: 'topo2',
-        VERSION: '1.1.1'
-      }
-    })
-  });
-  
-  // The layer for putting the data
-  var features = new ol.Collection();
+    var features = new ol.Collection();
 
 var iconRadius = 10;
     
@@ -150,64 +97,69 @@ var styles = {
   });
   
   
+  var parser = new ol.format.WMTSCapabilities();
+  fetch('https://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabilities').then(function(response) {
+        return response.text();
+      }).then(function(text) {
+        var result = parser.read(text);
+        var options = ol.source.WMTS.optionsFromCapabilities(result, {
+          layer: 'topo4',
+          matrixSet: 'EPSG:3857'
+        });
+        var topo4 = 
+          new ol.layer.Tile({
+            opacity: 1,
+            source: new ol.source.WMTS(/** @type {!olx.source.WMTSOptions} */ (options))
+          });
+          
   
-  map = new ol.Map({
-        target: 'map',
-        layers: [
-          //topo2graatone, 
-          topo2,
-          //osm,
-          featureOverlay,
-          newFeatureOverlay
-        ],
-        view: new ol.View({
-          center: ol.proj.fromLonLat([8.5, 60.8]),
-          zoom: 6
-        })
-      });
-    
-    // TODO feature properties must be synchronized
-    var lastYear = new Date().getFullYear() - 1;
-    // Population the season select list, setting last year as default selected
-    initSeasonSelectList(lastYear);
-    getAndRenderObservations(lastYear);
-    /*
-    $.getJSON("/rest/observation/filter/1/geoJSON?from=" + lastYear + "-01-01&pestId=" + paerebrann.organismId, function(geoData){
-        //console.info(geoData)
-        var format = new ol.format.GeoJSON();
+        map = new ol.Map({
+              target: 'map',
+              layers: [
+                //topo2graatone, 
+                topo4,
+                //osm,
+                featureOverlay,
+                newFeatureOverlay
+              ],
+              view: new ol.View({
+                center: ol.proj.fromLonLat([8.5, 60.8]),
+                zoom: 6
+              })
+            });
 
-        var drawnfeatures = format.readFeatures(geoData, {
-          //dataProjection: "EPSG:32633",
-          dataProjection: "EPSG:4326",
-          featureProjection: map.getView().getProjection().getCode()
+        // TODO feature properties must be synchronized
+        var lastYear = new Date().getFullYear() - 1;
+        // Population the season select list, setting last year as default selected
+        initSeasonSelectList(lastYear);
+        getAndRenderObservations(lastYear);
+
+
+        map.on('click', function(evt){
+                //features = []
+                var feature = map.forEachFeatureAtPixel(
+                    evt.pixel, function(ft, l) { return ft; }
+                );
+
+                var vectorSource = newFeatureOverlay.getSource();
+                // Remove any new features already created
+                vectorSource.clear();
+
+                if (feature) {
+                    // Create a fake icon for highlighting
+                    var fakeFeature = createFeature(feature.getGeometry().getCoordinates());
+                    vectorSource.addFeature(fakeFeature);
+                    displayFeature(feature);   
+                }
+                else if(registration)
+                {
+                    var newFeature = createFeature(map.getCoordinateFromPixel(evt.pixel));
+                    vectorSource.addFeature(newFeature);
+                    editFeature(newFeature.getId());
+                }
         });
-        //featureOverlay.clear(true);
-        featureOverlay.getSource().addFeatures(drawnfeatures);
-    });*/
     
-    map.on('click', function(evt){
-        //features = []
-        var feature = map.forEachFeatureAtPixel(
-            evt.pixel, function(ft, l) { return ft; }
-        );
-
-        var vectorSource = newFeatureOverlay.getSource();
-        // Remove any new features already created
-        vectorSource.clear();
-
-        if (feature) {
-            // Create a fake icon for highlighting
-            var fakeFeature = createFeature(feature.getGeometry().getCoordinates());
-            vectorSource.addFeature(fakeFeature);
-            displayFeature(feature);   
-        }
-        else if(registration)
-        {
-            var newFeature = createFeature(map.getCoordinateFromPixel(evt.pixel));
-            vectorSource.addFeature(newFeature);
-            editFeature(newFeature.getId());
-        }
-    });
+    }); // END FETCH
     
 }
 
diff --git a/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js b/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js
index 9a25f8847289675d1f0685c5d74a33390ac9c980..f992d1b1111ded2d3c921e91be1ac9aff80e0586 100644
--- a/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js
+++ b/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js
@@ -178,18 +178,15 @@ function parseJSONDate(theDateString)
 
 function getTodayAtMidnight()
 {
-    var retVal = new Date();
-    retVal.setHours(0);
-    retVal.setMinutes(0);
-    retVal.setSeconds(0);
-    retVal.setMilliseconds(0);
+    var now = new Date();
     
-    //return retVal;
+    var midnightString = now.getFullYear() + "-" + 
+                            ('0' + (now.getMonth()+1)).slice(-2) + "-" +
+                            ('0' + (now.getDate()-1)).slice(-2) + 
+                            "T22:00:00.000+0000";
+    return new Date(midnightString);
     // OR RETURN A FIXED DATE FOR TESTING
-    retVal.setFullYear(2017);
-    retVal.setMonth(8); // September
-    retVal.setDate(9);
-    return retVal;//new Date("2017-09-09T22:00:00.000+0000");
+    return new Date("2017-09-07T22:00:00.000+0000");
 }
 
 
diff --git a/src/main/webapp/templates/appleFruitMothClusterForm.ftl b/src/main/webapp/templates/appleFruitMothClusterForm.ftl
index a1042cc8a4388122573e59732e2c97857281157d..4e50de7fa029e049a34873971691b4b45d817799 100644
--- a/src/main/webapp/templates/appleFruitMothClusterForm.ftl
+++ b/src/main/webapp/templates/appleFruitMothClusterForm.ftl
@@ -24,12 +24,14 @@
    <#if messageKey?has_content>
             <div class="alert alert-success">${.now}: ${i18nBundle(messageKey)}</div>
     </#if>
+    <button type="button" class="btn btn-default" onclick="window.location='/applefruitmoth';"><i class="fa fa-arrow-left" aria-hidden="true"></i> Tilbake til stasjonsliste</button>
+    <#if user.isSuperUser() || user.isAppleFruitMothAdministrator() ><button class="btn btn-default" type="button" onclick="window.location='/applefruitmoth?action=viewObservationSite&observationSiteId=${observationSite.observationSiteId}';">Rediger ${observationSite.observationSiteName}</button></#if>
+                   
    <div class="singleBlockContainer">
 	
 	<div class="row">
             <form role="form" action="/applefruitmoth?action=clusterSubmit" method="POST" onsubmit="return validateForm(this)">
 		<div class="col-md-8">
-                    <button type="button" class="btn btn-default" onclick="window.location='/applefruitmoth';"><i class="fa fa-arrow-left" aria-hidden="true"></i> Tilbake</button>
                     <p>
                     Man trenger ikke registrere informasjon for alle trær (A-T) i 
                     lista. Et tre kan ha bare høsttallet registrert, men ikke bare vårtallet
diff --git a/src/main/webapp/templates/appleFruitMothStationForm.ftl b/src/main/webapp/templates/appleFruitMothStationForm.ftl
index 07e4436c892907f5d6539dcf116496d4709f3236..a8de8304e7b13ba5e9f760492e165b97e42a7b65 100755
--- a/src/main/webapp/templates/appleFruitMothStationForm.ftl
+++ b/src/main/webapp/templates/appleFruitMothStationForm.ftl
@@ -26,6 +26,7 @@
 	<script src="/js/resourcebundle.js"></script>
 	<script type="text/javascript" src="/js/3rdparty/ol.js"></script>
 	<script type="text/javascript" src="/js/constants.js"></script>
+        <script type="text/javascript" src="/js/validateForm.js"></script>
 	<script type="text/javascript" src="/js/appleFruitMothObservationSiteMap.js"></script>
 	<script type="text/javascript">
 		$(document).ready(function() {
@@ -35,16 +36,17 @@
 </#macro>
 <#macro page_contents>
 <h1>${observationSite.observationSiteName!i18nBundle.newObservationSite} ${currentSeason}</h1>
-<button type="button" class="btn btn-default" onclick="window.location='/applefruitmoth';"><i class="fa fa-arrow-left" aria-hidden="true"></i> ${i18nBundle.back}</button>
+<button type="button" class="btn btn-default" onclick="window.location='/applefruitmoth';"><i class="fa fa-arrow-left" aria-hidden="true"></i> Tilbake til stasjonsliste</button>
 <button type="button" class="btn btn-default" onclick="window.location='/applefruitmoth?action=registerCluster&observationSiteId=${observationSite.observationSiteId}&currentSeason=${currentSeason}';">Registrer klasetall</button>
 <div class="singleBlockContainer">
 	
 	<div class="row">
 		<div class="col-md-6">
-			<#assign formId = "observationSiteForm">
+			<#assign formId = "appleFruitMothStationForm">
 			<#if messageKey?has_content>
 				<div class="alert alert-success">${.now}: ${i18nBundle(messageKey)}</div>
 			</#if>
+                        <#if observationSiteSeasonCommonData??><div class="alert alert-info">${i18nBundle.lastUpdated}: ${observationSiteSeasonCommonData.lastUpdated}</div></#if>
 			<form id="${formId}" role="form" action="/applefruitmoth?action=observationSiteSubmit" method="POST">
 				<input type="hidden" name="observationSiteId" value="${observationSite.observationSiteId}"/>
 				<div class="form-group">
@@ -74,12 +76,12 @@
 				  </div>
 				<div class="form-group">
 				    <label for="degreeOfParasitation">${i18nBundle.degreeOfParasitation} (${i18nBundle.internal})</label>
-				    <input type="number" class="form-control" name="degreeOfParasitation" placeholder="${i18nBundle.degreeOfParasitation}" value="<#if observationSiteSeasonCommonData??>${observationSiteSeasonCommonData.degreeOfParasitation!""}</#if>" onblur="validateField(this);" />
+				    <input type="number" step="any" class="form-control" name="degreeOfParasitation" placeholder="${i18nBundle.degreeOfParasitation}" value="<#if observationSiteSeasonCommonData??>${observationSiteSeasonCommonData.degreeOfParasitation?c!""}</#if>" onblur="validateField(this);" />
 				    <span class="help-block" id="${formId}_degreeOfParasitation_validation"></span>
 				</div>
 				<div class="form-group">
 				    <label for="thousandBerrySample">${i18nBundle.thousandBerrySample} (${i18nBundle.internal})</label>
-				    <input type="number" class="form-control" name="thousandBerrySample" placeholder="${i18nBundle.thousandBerrySample}" value="<#if observationSiteSeasonCommonData??>${observationSiteSeasonCommonData.thousandBerrySample!""}</#if>" onblur="validateField(this);" />
+				    <input type="number" step="any" class="form-control" name="thousandBerrySample" placeholder="${i18nBundle.thousandBerrySample}" value="<#if observationSiteSeasonCommonData??>${observationSiteSeasonCommonData.thousandBerrySample?c!""}</#if>" onblur="validateField(this);" />
 				    <span class="help-block" id="${formId}_thousandBerrySample_validation"></span>
 				</div>
                                 <div class="form-group">
@@ -102,10 +104,10 @@
                             <tr><td>Antall trær med økning i klasetall over vinteren</td><td>${treesWithIncreasingValues}</td></tr>
                             <tr><td>Antall trær med nedgang i klasetall over vinteren</td><td>${treesWithDecreasingValues}</td></tr>
                             <tr><td>Antall trær med uendret klasetall over vinteren</td><td>${treesWithUnchangedValues}</td></tr>
-                            <tr><td>Angrepstall</td><td>${attackNumber!"[Data mangler]"}%</td></tr>
+                            <tr><td>Angrepstall</td><td><#if attackNumber??>${attackNumber?c}<#else>[Data mangler]</#if></td></tr>
                             <tr><td>Nødvendig antall klaser ${currentSeason}</td><td>${neededClusters!"[Data mangler]"}</td></tr>
-                            <tr><td>Prognosetall ${currentSeason}</td><td>${forecastNumber!"[Data mangler]"}</td></tr>
-                            <tr><td>Klasebrøk</td><td>${clusterFraction!"[Data mangler]"}</td></tr>
+                            <tr><td>Prognosetall ${currentSeason}</td><td><#if forecastNumber??>${forecastNumber}<#else>[Data mangler]</#if></td></tr>
+                            <tr><td>Klasebrøk</td><td><#if clusterFraction??>${clusterFraction?c}<#else>[Data mangler]</#if></td></tr>
                             
                         </tbody>
                         </table>
diff --git a/src/main/webapp/templates/appleFruitMothStationList.ftl b/src/main/webapp/templates/appleFruitMothStationList.ftl
index d725953bf69a56c06f9d115c0416eb0f99478e90..e86ade492a79a7366d676b3a6d7a80aae52ccb8f 100755
--- a/src/main/webapp/templates/appleFruitMothStationList.ftl
+++ b/src/main/webapp/templates/appleFruitMothStationList.ftl
@@ -39,11 +39,16 @@
 	<div class="row">
 		<div class="col-md-6">
 			<table class="table table-striped">
+                            <tr>
+                                <td colspan="3"></td>
+                                <th>Klasetall sist oppdatert</th>
+                            </tr>
                             <#list observationSites as observationSite>
                             <tr>
                                 <td>${observationSite.observationSiteName}</td>
                                 <td><#if user.isSuperUser() || user.isAppleFruitMothAdministrator() ><button class="btn btn-default" onclick="window.location='/applefruitmoth?action=viewObservationSite&observationSiteId=${observationSite.observationSiteId}';">Rediger</button></#if></td>
                                 <td><button class="btn btn-default" onclick="window.location='/applefruitmoth?action=registerCluster&observationSiteId=${observationSite.observationSiteId}';">Registrer klasetall</button></td>
+                                <td>${observationSite.lastUpdatedClusterCount!"Ukjent"}</td>
                             </tr>
                             </#list>
 			</table>
diff --git a/src/main/webapp/templates/forecastConfigurationForm.ftl b/src/main/webapp/templates/forecastConfigurationForm.ftl
index 637f74c785b5590f0edd79c023f5e52c15a621cb..803f5600cc96fd4fede4fbd35d3b2b0d9494d572 100755
--- a/src/main/webapp/templates/forecastConfigurationForm.ftl
+++ b/src/main/webapp/templates/forecastConfigurationForm.ftl
@@ -26,6 +26,7 @@
 	<link href="//code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" />
 	<script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script>
 	<script type="text/javascript" src="/js/3rdparty/moment.min.js"></script>
+        <script type="text/javascript" src="/js/environment.js"></script>
         <script type="text/javascript" src="/js/util.js"></script>
 	<script type="text/javascript">
             $(document).ready(function() {
@@ -44,8 +45,11 @@
 			renderModelSpecificFields("${formId}");
                         
 		}
-                    
-                initCropCategories();
+                
+                if(document.getElementById("cropCategoryIdList") != null)
+                {
+                    initCropCategories();
+                }
                     
                 sortListAlphabetically(document.getElementById("modelId"),1);
             });
@@ -60,7 +64,7 @@
             }
 
             function renderCropCategories() {
-                var cropCategoryIdList = document.getElementById("cropCategoryIdList");
+                var cropCategoryIdList = document.getElementById("cropCategoryIdList");                    
                 for(var i in cropCategories)
                 {
                     var cropCategory = cropCategories[i];
diff --git a/src/main/webapp/templates/observationMap.ftl b/src/main/webapp/templates/observationMap.ftl
index f9f67e0c7b4370babdbe2b7a39afe36bf5be0499..4adc17aa76a196a5c2ca470c2d7d841a49e0b5d6 100755
--- a/src/main/webapp/templates/observationMap.ftl
+++ b/src/main/webapp/templates/observationMap.ftl
@@ -95,9 +95,9 @@
                     var html = "<ul>";
                     for(var i in colors)
                     {
-                            html += '<li><i style="color: ' + colors[i][1] + ';" class="fa fa-square" aria-hidden="true"></i> ' + (i > 0 ? colors[i-1][0] + 1 : '0') + '-' + colors[i][0] + ' dager</li>';
+                            html += '<li><i style="color: ' + colors[i][1] + ';" class="fa fa-square" aria-hidden="true"></i> ' + (i > 0 ? colors[i-1][0] + 1 : '0') + '-' + colors[i][0] + ' ${i18nBundle.days?lower_case}</li>';
                     }
-                        html += '<li><i style="color: black;" class="fa fa-square" aria-hidden="true"></i> Eldre</li>';
+                        html += '<li><i style="color: black;" class="fa fa-square" aria-hidden="true"></i> ${i18nBundle.older}</li>';
                     html += "</ul>";
                     lBox.innerHTML = html;
                 }
@@ -159,7 +159,7 @@
         <div id="observationMap" class="map" style="position:relative;">
             <div id="popover"></div>
             <div class="form-group" id="progressBar">
-                <label for="dayInPeriod">Gjeldende dato: <span id="dayInPeriodDate">${to?date}</span></label><br/>
+                <label for="dayInPeriod">${i18nBundle.currentDate}: <span id="dayInPeriodDate">${to?date}</span></label><br/>
                 <button type="button" id="playButton" class="btn" onclick="togglePlay(this);"><i class="fa fa-play" aria-hidden="true"></i></button>
                 <input type="range" id="dayInPeriod" name="dayInPeriod" min="1" max="${periodDays}" step="1" value="${periodDays}" oninput="updateCurrentDate(this);" onchange="updateMap(this)"/>
                 
diff --git a/src/test/java/no/nibio/vips/util/weather/MetosAPIDataParserTest.java b/src/test/java/no/nibio/vips/util/weather/MetosAPIDataParserTest.java
index 78f553258053142f9236135f1bd523c8acd7176c..555d900980222172c33838b0974bd35253b91c60 100644
--- a/src/test/java/no/nibio/vips/util/weather/MetosAPIDataParserTest.java
+++ b/src/test/java/no/nibio/vips/util/weather/MetosAPIDataParserTest.java
@@ -79,7 +79,7 @@ public class MetosAPIDataParserTest {
         MetosAPIDataParser instance = new MetosAPIDataParser();
         List<WeatherObservation> result = instance.getWeatherObservations(stationId, timeZone, startDate);
         assertNotNull( result);
-        //result.stream().forEach(obs -> System.out.println(obs.toString()));
+        result.stream().forEach(obs -> System.out.println(obs.toString()));
         
     }