diff --git a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
index 46369ffb32da787c725cd63a1cc723a367f010bd..add6f3ca1a78108657c6c94ce1391f987293633e 100644
--- a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
+++ b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java
@@ -51,6 +51,7 @@ public class VIPSLogicApplication extends Application
         resources.add(no.nibio.vips.logic.modules.roughage.RoughageService.class);
         resources.add(no.nibio.vips.observationdata.ObservationDataService.class);
         resources.add(no.nibio.vips.logic.messaging.sms.SMSHandlingService.class);
+        resources.add(no.nibio.vips.logic.modules.applefruitmoth.AppleFruitMothService.class);
         //resources.add(no.nibio.vips.logic.service.JacksonConfig.class);
         //resources.add(no.nibio.vips.coremanager.service.ManagerResourceImpl.class);
     }
@@ -63,6 +64,7 @@ public class VIPSLogicApplication extends Application
     private void addRestResourceClasses(Set<Class<?>> resources) {
         
         resources.add(no.nibio.vips.logic.messaging.sms.SMSHandlingService.class);
+        resources.add(no.nibio.vips.logic.modules.applefruitmoth.AppleFruitMothService.class);
         resources.add(no.nibio.vips.logic.modules.barleynetblotch.BarleyNetBlotchModelService.class);
         resources.add(no.nibio.vips.logic.modules.roughage.RoughageService.class);
         resources.add(no.nibio.vips.logic.service.JacksonConfig.class);
diff --git a/src/main/java/no/nibio/vips/logic/gis/GeometryEntity.java b/src/main/java/no/nibio/vips/logic/gis/GeometryEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..0654bf27e987fe3d5aabc2d9661973ba47dd56ef
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/gis/GeometryEntity.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 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.gis;
+
+import com.vividsolutions.jts.geom.Geometry;
+import java.io.Serializable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import org.hibernate.annotations.Type;
+
+/**
+ * This entity enables native querying of PostGIS Geometry elements in the database, 
+ * mapping to Java Topology Suite Geometry object. Example of usage:
+ * <pre>Query q = em.createNativeQuery("SELECT 1 as id, ST_Centroid(ST_Union(gis_geom)) AS geometry_value FROM public.gis WHERE gis_id IN ("
+                    + "     SELECT gis_id "
+                    + "     FROM applefruitmoth.observation_site_point "
+                    + "     WHERE observation_site_id = :observationSiteId"
+                    + ")", GeometryEntity.class);
+            
+            GeometryEntity o = (GeometryEntity) q.setParameter("observationSiteId", observationSite.getObservationSiteId())
+                    .getSingleResult();
+            
+            return o.getGeometryValue();
+   </pre>
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+public class GeometryEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private Long id;
+    
+    @Type(type = "org.hibernate.spatial.GeometryType")
+    @Column(name = "geometry_value", columnDefinition = "Geometry")
+    private Geometry geometryValue;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+    
+    
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (id != null ? id.hashCode() : 0);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        // TODO: Warning - this method won't work in the case the id fields are not set
+        if (!(object instanceof GeometryEntity)) {
+            return false;
+        }
+        GeometryEntity other = (GeometryEntity) object;
+        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.applefruitmoth.GeometryEntity[ id=" + id + " ]";
+    }
+
+    /**
+     * @return the geometryValue
+     */
+    public Geometry getGeometryValue() {
+        return geometryValue;
+    }
+
+    /**
+     * @param geometryValue the geometryValue to set
+     */
+    public void setGeometryValue(Geometry geometryValue) {
+        this.geometryValue = geometryValue;
+    }
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..b5f876dd13fb9a5bac16d42d271e07ef4efcd550
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import no.nibio.vips.logic.gis.GeometryEntity;
+import com.vividsolutions.jts.geom.Geometry;
+import de.micromata.opengis.kml.v_2_2_0.Coordinate;
+import de.micromata.opengis.kml.v_2_2_0.Document;
+import de.micromata.opengis.kml.v_2_2_0.Kml;
+import de.micromata.opengis.kml.v_2_2_0.KmlFactory;
+import de.micromata.opengis.kml.v_2_2_0.Placemark;
+import de.micromata.opengis.kml.v_2_2_0.Point;
+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.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;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@LocalBean
+@Stateless
+public class AppleFruitMothBean {
+    @PersistenceContext(unitName="VIPSLogic-PU")
+    EntityManager em;
+    
+    public Geometry getObservationSiteCenter(ObservationSite observationSite)
+    {
+        try
+        {
+            Query q = em.createNativeQuery("SELECT :observationSiteId as id, ST_Centroid(ST_Union(gis_geom)) AS geometry_value FROM public.gis WHERE gis_id IN ("
+                    + "     SELECT gis_id "
+                    + "     FROM applefruitmoth.observation_site_point "
+                    + "     WHERE observation_site_id = :observationSiteId"
+                    + ")", GeometryEntity.class);
+            System.out.println(observationSite.getObservationSiteName() + " has id=" + observationSite.getObservationSiteId());
+            GeometryEntity o = (GeometryEntity) q.setParameter("observationSiteId", observationSite.getObservationSiteId())
+                    .getSingleResult();
+            System.out.println(o.getGeometryValue().toString());
+            return o.getGeometryValue();
+        }
+        catch(NoResultException ex)
+        {
+            return null;
+        }
+    }
+    
+    public List<ObservationSite> getObservationSites()
+    {
+        List<ObservationSite> sites = em.createNamedQuery("ObservationSite.findAll").getResultList();
+        for(ObservationSite site:sites)
+        {
+            site.setSiteCenterPoint(this.getObservationSiteCenter(site));
+        }
+        return sites;
+    }
+
+    public ObservationSite getObservationSite(Integer observationSiteId) {
+        return em.find(ObservationSite.class, observationSiteId);
+    }
+
+    public Kml getObservationSitesKml(Integer season, String serverName) {
+        String iconPath = "http://" + serverName + "/public/images/";
+        // Initialization
+        final Vec2 hotspot = new Vec2()
+                .withX(0.5)
+                .withXunits(Units.FRACTION)
+                .withY(0)
+                .withYunits(Units.FRACTION);
+        final Kml kml = KmlFactory.createKml();
+        final Document document = kml.createAndSetDocument()
+                .withName("Rognebærmøllstasjoner").withDescription("Oversikt over varslingssesongen " + season);
+        
+        // Adding icons for warning statuses
+        document.createAndAddStyle()
+            .withId("warning_type_0")
+        .createAndSetIconStyle()
+                .withScale(1)
+                .withHotSpot(hotspot)
+                .createAndSetIcon()
+                    .withHref(iconPath + "station_icon_status_0.png");
+        
+        document.createAndAddStyle()
+            .withId("warning_type_1")
+        .createAndSetIconStyle()
+                .withScale(1)
+                .withHotSpot(hotspot)
+                .createAndSetIcon()
+                    .withHref(iconPath + "station_icon_status_1.png");
+        
+        document.createAndAddStyle()
+            .withId("warning_type_2")
+        .createAndSetIconStyle()
+                .withScale(1)
+                .withHotSpot(hotspot)
+                .createAndSetIcon()
+                    .withHref(iconPath + "station_icon_status_2.png");
+        
+        document.createAndAddStyle()
+            .withId("warning_type_3")
+        .createAndSetIconStyle()
+                .withScale(1)
+                .withHotSpot(hotspot)
+                .createAndSetIcon()
+                    .withHref(iconPath + "station_icon_status_3.png");
+        
+        document.createAndAddStyle()
+            .withId("warning_type_4")
+        .createAndSetIconStyle()
+                .withScale(1)
+                .withHotSpot(hotspot)
+                .createAndSetIcon()
+                    .withHref(iconPath + "station_icon_status_4.png");
+        
+        List<ObservationSite> sites = this.getObservationSites();
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+        for(ObservationSite site:sites)
+        {
+            Integer warningStatus = 0;
+            String remarks = "Varsel ikke oppdatert";
+            ObservationSiteSeasonCommonData commonData = site.getCommonDataForSeason(season);
+            if(commonData != null)
+            {
+                warningStatus = commonData.getWarningStatus();
+                String lastUpdatedStr = "";
+                if(commonData.getLastUpdated() != null)
+                {
+                    lastUpdatedStr = "[" + format.format(commonData.getLastUpdated()) + "] ";
+                }
+                remarks = lastUpdatedStr + (commonData.getRemarks() != null ? commonData.getRemarks() : "");
+            }
+            final Placemark placemark = document.createAndAddPlacemark()
+                    .withName(site.getObservationSiteName())
+                    .withDescription(remarks)
+                    .withStyleUrl("#warning_type_" + warningStatus)
+                    .withId(site.getObservationSiteId().toString());
+            
+            Geometry siteCenter = this.getObservationSiteCenter(site);
+            System.out.println("siteCenter for " + site.getObservationSiteName() + "=" + siteCenter.toString());
+            final Point point = placemark.createAndSetPoint();
+            List<Coordinate> coord = point.createAndSetCoordinates();
+            coord.add(new Coordinate(
+                    siteCenter.getCoordinate().x,
+                    siteCenter.getCoordinate().y,
+                    0
+            ));
+            
+        }
+        return kml;
+    }
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..dd6044fe279954a13e816ea6d19f61f3df33b009
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import com.ibm.icu.util.Calendar;
+import java.io.IOException;
+import java.util.List;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import no.nibio.vips.logic.entity.VipsLogicRole;
+import no.nibio.vips.logic.entity.VipsLogicUser;
+import no.nibio.vips.logic.util.SessionControllerGetter;
+import no.nibio.vips.logic.util.SystemTime;
+import no.nibio.vips.util.ExceptionUtil;
+
+/**
+ *
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+public class AppleFruitMothController extends HttpServlet {
+
+    /**
+     * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
+     * methods.
+     *
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+        response.setContentType("text/html;charset=UTF-8");
+        VipsLogicUser user = (VipsLogicUser) request.getSession().getAttribute("user");
+        if(SessionControllerGetter.getUserBean().authorizeUser(user, VipsLogicRole.APPLE_FRUIT_MOTH_ADMINISTRATOR, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER))
+        {
+            String action = request.getParameter("action");
+            if(action == null)
+            {
+                // Show map and list of existing stations
+                List<ObservationSite> observationSites = SessionControllerGetter.getAppleFruitMothBean().getObservationSites();
+                request.setAttribute("observationSites", observationSites);
+                request.getRequestDispatcher("/appleFruitMothStationList.ftl").forward(request, response);
+            }
+            else if(action.equals("viewObservationSite"))
+            {
+                try
+                {
+                    Integer observationSiteId = Integer.valueOf(request.getParameter("observationSiteId"));
+                    Calendar cal = Calendar.getInstance();
+                    cal.setTime(SystemTime.getSystemTime());
+                    Integer lastSeason = cal.get(Calendar.YEAR);
+                    Integer currentSeason = request.getParameter("currentSeason") != null ? Integer.valueOf(request.getParameter("currentSeason")) : lastSeason;
+                    ObservationSite observationSite = SessionControllerGetter.getAppleFruitMothBean().getObservationSite(observationSiteId);
+                    request.setAttribute("observationSite", observationSite);
+                    if(observationSite != null)
+                    {
+                        request.setAttribute("observationSiteSeasonCommonData", observationSite.getCommonDataForSeason(currentSeason));
+                        request.setAttribute("observationSitePoints", observationSite.getObservationSitePointSet());
+                    }
+                    request.setAttribute("currentSeason", currentSeason);
+                    request.setAttribute("lastSeason", lastSeason);
+                    request.getRequestDispatcher("/appleFruitMothStationForm.ftl").forward(request, response);
+                }
+                catch(NullPointerException | NumberFormatException ex)
+                {
+                    response.sendError(500, ExceptionUtil.getStackTrace(ex));
+                }
+            }
+        }
+        else
+        {
+            response.sendError(403,"Access not authorized"); // HTTP Forbidden
+        }
+    }
+
+    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
+    /**
+     * Handles the HTTP <code>GET</code> method.
+     *
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+        processRequest(request, response);
+    }
+
+    /**
+     * Handles the HTTP <code>POST</code> method.
+     *
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    protected void doPost(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+        processRequest(request, response);
+    }
+
+    /**
+     * Returns a short description of the servlet.
+     *
+     * @return a String containing servlet description
+     */
+    @Override
+    public String getServletInfo() {
+        return "Short description";
+    }// </editor-fold>
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothService.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothService.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e6bd003cabdac81b87868ea8e8cefcfd8b77a44
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothService.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import de.micromata.opengis.kml.v_2_2_0.Kml;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import no.nibio.vips.logic.util.SessionControllerGetter;
+import no.nibio.vips.util.ServletUtil;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Path("rest/applefruitmoth")
+public class AppleFruitMothService {
+    
+    @Context
+    private HttpServletRequest httpServletRequest;
+    
+    @GET
+    @Path("observationsites/kml/{season}")
+    @Produces("application/vnd.google-earth.kml+xml;charset=utf-8")
+    public Response getObservationSitesKML(@PathParam("season") Integer season)
+    {
+        Kml retVal = SessionControllerGetter.getAppleFruitMothBean().getObservationSitesKml(season, ServletUtil.getServerName(httpServletRequest));
+        return Response.ok().entity(retVal).build();
+    }
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..bc963b6386932283062ae49125264bc04525e3fe
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import com.vividsolutions.jts.geom.Geometry;
+import java.io.Serializable;
+import java.util.Set;
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "observation_site", schema="applefruitmoth")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "ObservationSite.findAll", query = "SELECT o FROM ObservationSite o"),
+    @NamedQuery(name = "ObservationSite.findByObservationSiteId", query = "SELECT o FROM ObservationSite o WHERE o.observationSiteId = :observationSiteId"),
+    @NamedQuery(name = "ObservationSite.findByObservationSiteName", query = "SELECT o FROM ObservationSite o WHERE o.observationSiteName = :observationSiteName")})
+public class ObservationSite implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Basic(optional = false)
+    @Column(name = "observation_site_id")
+    private Integer observationSiteId;
+    @Size(max = 127)
+    @Column(name = "observation_site_name")
+    private String observationSiteName;
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "observationSite", fetch = FetchType.EAGER)
+    private Set<ObservationSiteSeasonCommonData> observationSiteSeasonCommonDataSet;
+    @OneToMany(mappedBy = "observationSiteId", fetch = FetchType.EAGER)
+    private Set<ObservationSitePoint> observationSitePointSet;
+    @Transient
+    private Geometry siteCenterPoint;
+
+    public ObservationSite() {
+    }
+
+    public ObservationSite(Integer observationSiteId) {
+        this.observationSiteId = observationSiteId;
+    }
+
+    public Integer getObservationSiteId() {
+        return observationSiteId;
+    }
+
+    public void setObservationSiteId(Integer observationSiteId) {
+        this.observationSiteId = observationSiteId;
+    }
+
+    public String getObservationSiteName() {
+        return observationSiteName;
+    }
+
+    public void setObservationSiteName(String observationSiteName) {
+        this.observationSiteName = observationSiteName;
+    }
+
+    @XmlTransient
+    public Set<ObservationSiteSeasonCommonData> getObservationSiteSeasonCommonDataSet() {
+        return observationSiteSeasonCommonDataSet;
+    }
+
+    public void setObservationSiteSeasonCommonDataSet(Set<ObservationSiteSeasonCommonData> observationSiteSeasonCommonDataSet) {
+        this.observationSiteSeasonCommonDataSet = observationSiteSeasonCommonDataSet;
+    }
+
+    @XmlTransient
+    public Set<ObservationSitePoint> getObservationSitePointSet() {
+        return observationSitePointSet;
+    }
+
+    public void setObservationSitePointSet(Set<ObservationSitePoint> observationSitePointSet) {
+        this.observationSitePointSet = observationSitePointSet;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (observationSiteId != null ? observationSiteId.hashCode() : 0);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        // TODO: Warning - this method won't work in the case the id fields are not set
+        if (!(object instanceof ObservationSite)) {
+            return false;
+        }
+        ObservationSite other = (ObservationSite) object;
+        if ((this.observationSiteId == null && other.observationSiteId != null) || (this.observationSiteId != null && !this.observationSiteId.equals(other.observationSiteId))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.applefruitmoth.ObservationSite[ observationSiteId=" + observationSiteId + " ]";
+    }
+
+    /**
+     * @return the siteCenterPoint
+     */
+    public Geometry getSiteCenterPoint() {
+        return siteCenterPoint;
+    }
+
+    /**
+     * @param siteCenterPoint the siteCenterPoint to set
+     */
+    public void setSiteCenterPoint(Geometry siteCenterPoint) {
+        this.siteCenterPoint = siteCenterPoint;
+    }
+    
+    @Transient
+    public ObservationSiteSeasonCommonData getCommonDataForSeason(Integer season)
+    {
+        for(ObservationSiteSeasonCommonData cd : observationSiteSeasonCommonDataSet)
+        {
+            if(cd.getObservationSiteSeasonCommonDataPK().getSeason() == season)
+            {
+                return cd;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePoint.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePoint.java
new file mode 100644
index 0000000000000000000000000000000000000000..c74a666f11d4eeecde0c9780d9d2075884836df0
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePoint.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import java.io.Serializable;
+import java.util.Set;
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "observation_site_point", schema="applefruitmoth")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "ObservationSitePoint.findAll", query = "SELECT o FROM ObservationSitePoint o"),
+    @NamedQuery(name = "ObservationSitePoint.findByObservationSitePointId", query = "SELECT o FROM ObservationSitePoint o WHERE o.observationSitePointId = :observationSitePointId"),
+    @NamedQuery(name = "ObservationSitePoint.findByPointName", query = "SELECT o FROM ObservationSitePoint o WHERE o.pointName = :pointName"),
+    @NamedQuery(name = "ObservationSitePoint.findByDescription", query = "SELECT o FROM ObservationSitePoint o WHERE o.description = :description"),
+    @NamedQuery(name = "ObservationSitePoint.findByGisId", query = "SELECT o FROM ObservationSitePoint o WHERE o.gisId = :gisId")})
+public class ObservationSitePoint implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Basic(optional = false)
+    @Column(name = "observation_site_point_id")
+    private Integer observationSitePointId;
+    @Size(max = 63)
+    @Column(name = "point_name")
+    private String pointName;
+    @Size(max = 2147483647)
+    @Column(name = "description")
+    private String description;
+    @Column(name = "gis_id")
+    private Integer gisId;
+    @JoinColumn(name = "observation_site_id", referencedColumnName = "observation_site_id")
+    @ManyToOne
+    private ObservationSite observationSiteId;
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "observationSitePoint", fetch = FetchType.EAGER)
+    private Set<ObservationSitePointSeasonData> observationSitePointSeasonDataSet;
+
+    public ObservationSitePoint() {
+    }
+
+    public ObservationSitePoint(Integer observationSitePointId) {
+        this.observationSitePointId = observationSitePointId;
+    }
+
+    public Integer getObservationSitePointId() {
+        return observationSitePointId;
+    }
+
+    public void setObservationSitePointId(Integer observationSitePointId) {
+        this.observationSitePointId = observationSitePointId;
+    }
+
+    public String getPointName() {
+        return pointName;
+    }
+
+    public void setPointName(String pointName) {
+        this.pointName = pointName;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getGisId() {
+        return gisId;
+    }
+
+    public void setGisId(Integer gisId) {
+        this.gisId = gisId;
+    }
+
+    public ObservationSite getObservationSiteId() {
+        return observationSiteId;
+    }
+
+    public void setObservationSiteId(ObservationSite observationSiteId) {
+        this.observationSiteId = observationSiteId;
+    }
+
+    @XmlTransient
+    public Set<ObservationSitePointSeasonData> getObservationSitePointSeasonDataSet() {
+        return observationSitePointSeasonDataSet;
+    }
+
+    public void setObservationSitePointSeasonDataSet(Set<ObservationSitePointSeasonData> observationSitePointSeasonDataSet) {
+        this.observationSitePointSeasonDataSet = observationSitePointSeasonDataSet;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (observationSitePointId != null ? observationSitePointId.hashCode() : 0);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        // TODO: Warning - this method won't work in the case the id fields are not set
+        if (!(object instanceof ObservationSitePoint)) {
+            return false;
+        }
+        ObservationSitePoint other = (ObservationSitePoint) object;
+        if ((this.observationSitePointId == null && other.observationSitePointId != null) || (this.observationSitePointId != null && !this.observationSitePointId.equals(other.observationSitePointId))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.applefruitmoth.ObservationSitePoint[ observationSitePointId=" + observationSitePointId + " ]";
+    }
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..76bed92dfaa75e6370558255d7bb0c6446c0cebd
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+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;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "observation_site_point_season_data", schema = "applefruitmoth")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "ObservationSitePointSeasonData.findAll", query = "SELECT o FROM ObservationSitePointSeasonData o"),
+    @NamedQuery(name = "ObservationSitePointSeasonData.findByObservationSitePointId", query = "SELECT o FROM ObservationSitePointSeasonData o WHERE o.observationSitePointSeasonDataPK.observationSitePointId = :observationSitePointId"),
+    @NamedQuery(name = "ObservationSitePointSeasonData.findBySeason", query = "SELECT o FROM ObservationSitePointSeasonData o WHERE o.observationSitePointSeasonDataPK.season = :season"),
+    @NamedQuery(name = "ObservationSitePointSeasonData.findByAutumnDate", query = "SELECT o FROM ObservationSitePointSeasonData o WHERE o.autumnDate = :autumnDate"),
+    @NamedQuery(name = "ObservationSitePointSeasonData.findByAutumnValue", query = "SELECT o FROM ObservationSitePointSeasonData o WHERE o.autumnValue = :autumnValue"),
+    @NamedQuery(name = "ObservationSitePointSeasonData.findBySpringDate", query = "SELECT o FROM ObservationSitePointSeasonData o WHERE o.springDate = :springDate"),
+    @NamedQuery(name = "ObservationSitePointSeasonData.findBySpringValue", query = "SELECT o FROM ObservationSitePointSeasonData o WHERE o.springValue = :springValue")})
+public class ObservationSitePointSeasonData implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    @EmbeddedId
+    protected ObservationSitePointSeasonDataPK observationSitePointSeasonDataPK;
+    @Column(name = "autumn_date")
+    @Temporal(TemporalType.DATE)
+    private Date autumnDate;
+    @Column(name = "autumn_value")
+    private BigDecimal autumnValue;
+    @Column(name = "spring_date")
+    @Temporal(TemporalType.DATE)
+    private Date springDate;
+    @Column(name = "spring_value")
+    private BigDecimal springValue;
+    @JoinColumn(name = "observation_site_point_id", referencedColumnName = "observation_site_point_id", insertable = false, updatable = false)
+    @ManyToOne(optional = false)
+    private ObservationSitePoint observationSitePoint;
+
+    public ObservationSitePointSeasonData() {
+    }
+
+    public ObservationSitePointSeasonData(ObservationSitePointSeasonDataPK observationSitePointSeasonDataPK) {
+        this.observationSitePointSeasonDataPK = observationSitePointSeasonDataPK;
+    }
+
+    public ObservationSitePointSeasonData(int observationSitePointId, int season) {
+        this.observationSitePointSeasonDataPK = new ObservationSitePointSeasonDataPK(observationSitePointId, season);
+    }
+
+    public ObservationSitePointSeasonDataPK getObservationSitePointSeasonDataPK() {
+        return observationSitePointSeasonDataPK;
+    }
+
+    public void setObservationSitePointSeasonDataPK(ObservationSitePointSeasonDataPK observationSitePointSeasonDataPK) {
+        this.observationSitePointSeasonDataPK = observationSitePointSeasonDataPK;
+    }
+
+    public Date getAutumnDate() {
+        return autumnDate;
+    }
+
+    public void setAutumnDate(Date autumnDate) {
+        this.autumnDate = autumnDate;
+    }
+
+    public BigDecimal getAutumnValue() {
+        return autumnValue;
+    }
+
+    public void setAutumnValue(BigDecimal autumnValue) {
+        this.autumnValue = autumnValue;
+    }
+
+    public Date getSpringDate() {
+        return springDate;
+    }
+
+    public void setSpringDate(Date springDate) {
+        this.springDate = springDate;
+    }
+
+    public BigDecimal getSpringValue() {
+        return springValue;
+    }
+
+    public void setSpringValue(BigDecimal springValue) {
+        this.springValue = springValue;
+    }
+
+    public ObservationSitePoint getObservationSitePoint() {
+        return observationSitePoint;
+    }
+
+    public void setObservationSitePoint(ObservationSitePoint observationSitePoint) {
+        this.observationSitePoint = observationSitePoint;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (observationSitePointSeasonDataPK != null ? observationSitePointSeasonDataPK.hashCode() : 0);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        // TODO: Warning - this method won't work in the case the id fields are not set
+        if (!(object instanceof ObservationSitePointSeasonData)) {
+            return false;
+        }
+        ObservationSitePointSeasonData other = (ObservationSitePointSeasonData) object;
+        if ((this.observationSitePointSeasonDataPK == null && other.observationSitePointSeasonDataPK != null) || (this.observationSitePointSeasonDataPK != null && !this.observationSitePointSeasonDataPK.equals(other.observationSitePointSeasonDataPK))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.applefruitmoth.ObservationSitePointSeasonData[ observationSitePointSeasonDataPK=" + observationSitePointSeasonDataPK + " ]";
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonDataPK.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonDataPK.java
new file mode 100644
index 0000000000000000000000000000000000000000..80cdcd06306b675f632b9192aae04af42c1ffb7c
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonDataPK.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import java.io.Serializable;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Embeddable
+public class ObservationSitePointSeasonDataPK implements Serializable {
+
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "observation_site_point_id")
+    private int observationSitePointId;
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "season")
+    private int season;
+
+    public ObservationSitePointSeasonDataPK() {
+    }
+
+    public ObservationSitePointSeasonDataPK(int observationSitePointId, int season) {
+        this.observationSitePointId = observationSitePointId;
+        this.season = season;
+    }
+
+    public int getObservationSitePointId() {
+        return observationSitePointId;
+    }
+
+    public void setObservationSitePointId(int observationSitePointId) {
+        this.observationSitePointId = observationSitePointId;
+    }
+
+    public int getSeason() {
+        return season;
+    }
+
+    public void setSeason(int season) {
+        this.season = season;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (int) observationSitePointId;
+        hash += (int) season;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        // TODO: Warning - this method won't work in the case the id fields are not set
+        if (!(object instanceof ObservationSitePointSeasonDataPK)) {
+            return false;
+        }
+        ObservationSitePointSeasonDataPK other = (ObservationSitePointSeasonDataPK) object;
+        if (this.observationSitePointId != other.observationSitePointId) {
+            return false;
+        }
+        if (this.season != other.season) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.applefruitmoth.ObservationSitePointSeasonDataPK[ observationSitePointId=" + observationSitePointId + ", season=" + season + " ]";
+    }
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..fe9cbb5122abfb706ea2e588ea702bd9b5c97d0f
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Entity
+@Table(name = "observation_site_season_common_data", schema="applefruitmoth")
+@XmlRootElement
+@NamedQueries({
+    @NamedQuery(name = "ObservationSiteSeasonCommonData.findAll", query = "SELECT o FROM ObservationSiteSeasonCommonData o"),
+    @NamedQuery(name = "ObservationSiteSeasonCommonData.findByObservationSiteId", query = "SELECT o FROM ObservationSiteSeasonCommonData o WHERE o.observationSiteSeasonCommonDataPK.observationSiteId = :observationSiteId"),
+    @NamedQuery(name = "ObservationSiteSeasonCommonData.findBySeason", query = "SELECT o FROM ObservationSiteSeasonCommonData o WHERE o.observationSiteSeasonCommonDataPK.season = :season"),
+    @NamedQuery(name = "ObservationSiteSeasonCommonData.findByThousandBerrySample", query = "SELECT o FROM ObservationSiteSeasonCommonData o WHERE o.thousandBerrySample = :thousandBerrySample"),
+    @NamedQuery(name = "ObservationSiteSeasonCommonData.findByDegreeOfParasitation", query = "SELECT o FROM ObservationSiteSeasonCommonData o WHERE o.degreeOfParasitation = :degreeOfParasitation")})
+public class ObservationSiteSeasonCommonData implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    @EmbeddedId
+    protected ObservationSiteSeasonCommonDataPK observationSiteSeasonCommonDataPK;
+    @Column(name = "thousand_berry_sample")
+    private BigDecimal thousandBerrySample;
+    @Column(name = "degree_of_parasitation")
+    private BigDecimal degreeOfParasitation;
+    @Column(name = "warning_status")
+    private Integer warningStatus;
+    @Column(name = "remarks")
+    private String remarks;
+    @Column(name = "last_updated")
+    private Date lastUpdated;
+    @JoinColumn(name = "observation_site_id", referencedColumnName = "observation_site_id", insertable = false, updatable = false)
+    @ManyToOne(optional = false)
+    private ObservationSite observationSite;
+
+    public ObservationSiteSeasonCommonData() {
+    }
+
+    public ObservationSiteSeasonCommonData(ObservationSiteSeasonCommonDataPK observationSiteSeasonCommonDataPK) {
+        this.observationSiteSeasonCommonDataPK = observationSiteSeasonCommonDataPK;
+    }
+
+    public ObservationSiteSeasonCommonData(int observationSiteId, int season) {
+        this.observationSiteSeasonCommonDataPK = new ObservationSiteSeasonCommonDataPK(observationSiteId, season);
+    }
+
+    public ObservationSiteSeasonCommonDataPK getObservationSiteSeasonCommonDataPK() {
+        return observationSiteSeasonCommonDataPK;
+    }
+
+    public void setObservationSiteSeasonCommonDataPK(ObservationSiteSeasonCommonDataPK observationSiteSeasonCommonDataPK) {
+        this.observationSiteSeasonCommonDataPK = observationSiteSeasonCommonDataPK;
+    }
+
+    public BigDecimal getThousandBerrySample() {
+        return thousandBerrySample;
+    }
+
+    public void setThousandBerrySample(BigDecimal thousandBerrySample) {
+        this.thousandBerrySample = thousandBerrySample;
+    }
+
+    public BigDecimal getDegreeOfParasitation() {
+        return degreeOfParasitation;
+    }
+
+    public void setDegreeOfParasitation(BigDecimal degreeOfParasitation) {
+        this.degreeOfParasitation = degreeOfParasitation;
+    }
+
+    public ObservationSite getObservationSite() {
+        return observationSite;
+    }
+
+    public void setObservationSite(ObservationSite observationSite) {
+        this.observationSite = observationSite;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (observationSiteSeasonCommonDataPK != null ? observationSiteSeasonCommonDataPK.hashCode() : 0);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        // TODO: Warning - this method won't work in the case the id fields are not set
+        if (!(object instanceof ObservationSiteSeasonCommonData)) {
+            return false;
+        }
+        ObservationSiteSeasonCommonData other = (ObservationSiteSeasonCommonData) object;
+        if ((this.observationSiteSeasonCommonDataPK == null && other.observationSiteSeasonCommonDataPK != null) || (this.observationSiteSeasonCommonDataPK != null && !this.observationSiteSeasonCommonDataPK.equals(other.observationSiteSeasonCommonDataPK))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.applefruitmoth.ObservationSiteSeasonCommonData[ observationSiteSeasonCommonDataPK=" + observationSiteSeasonCommonDataPK + " ]";
+    }
+
+    /**
+     * @return the warningStatus
+     */
+    public Integer getWarningStatus() {
+        return warningStatus;
+    }
+
+    /**
+     * @param warningStatus the warningStatus to set
+     */
+    public void setWarningStatus(Integer warningStatus) {
+        this.warningStatus = warningStatus;
+    }
+
+    /**
+     * @return the remarks
+     */
+    public String getRemarks() {
+        return remarks;
+    }
+
+    /**
+     * @param remarks the remarks to set
+     */
+    public void setRemarks(String remarks) {
+        this.remarks = remarks;
+    }
+
+    /**
+     * @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/ObservationSiteSeasonCommonDataPK.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonDataPK.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea6e557c37dc38ac9d151408a988ef47eabec48a
--- /dev/null
+++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonDataPK.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016 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.modules.applefruitmoth;
+
+import java.io.Serializable;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a>
+ * @author Tor-Einar Skog <tor-einar.skog@nibio.no>
+ */
+@Embeddable
+public class ObservationSiteSeasonCommonDataPK implements Serializable {
+
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "observation_site_id")
+    private int observationSiteId;
+    @Basic(optional = false)
+    @NotNull
+    @Column(name = "season")
+    private int season;
+
+    public ObservationSiteSeasonCommonDataPK() {
+    }
+
+    public ObservationSiteSeasonCommonDataPK(int observationSiteId, int season) {
+        this.observationSiteId = observationSiteId;
+        this.season = season;
+    }
+
+    public int getObservationSiteId() {
+        return observationSiteId;
+    }
+
+    public void setObservationSiteId(int observationSiteId) {
+        this.observationSiteId = observationSiteId;
+    }
+
+    public int getSeason() {
+        return season;
+    }
+
+    public void setSeason(int season) {
+        this.season = season;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        hash += (int) observationSiteId;
+        hash += (int) season;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        // TODO: Warning - this method won't work in the case the id fields are not set
+        if (!(object instanceof ObservationSiteSeasonCommonDataPK)) {
+            return false;
+        }
+        ObservationSiteSeasonCommonDataPK other = (ObservationSiteSeasonCommonDataPK) object;
+        if (this.observationSiteId != other.observationSiteId) {
+            return false;
+        }
+        if (this.season != other.season) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "no.nibio.vips.logic.modules.applefruitmoth.ObservationSiteSeasonCommonDataPK[ observationSiteId=" + observationSiteId + ", season=" + season + " ]";
+    }
+
+}
diff --git a/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java b/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java
index 8b99f3d65ba45833845fbb6d8965e3adc6050a88..24e1dbae7d66b25d304290a0fb5a3c6b90817135 100644
--- a/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java
+++ b/src/main/java/no/nibio/vips/logic/util/SessionControllerGetter.java
@@ -29,6 +29,7 @@ import no.nibio.vips.logic.controller.session.MessageBean;
 import no.nibio.vips.logic.controller.session.ObservationBean;
 import no.nibio.vips.logic.controller.session.OrganismBean;
 import no.nibio.vips.logic.messaging.MessagingBean;
+import no.nibio.vips.logic.modules.applefruitmoth.AppleFruitMothBean;
 
 /**
  * @copyright 2013-2014 <a href="http://www.nibio.no/">NIBIO</a>
@@ -154,6 +155,21 @@ public class SessionControllerGetter {
         }
     }
     
+    public static AppleFruitMothBean getAppleFruitMothBean()
+    {
+        try
+        {
+            InitialContext ic = new InitialContext();
+            AppleFruitMothBean retVal = (AppleFruitMothBean) ic.lookup(SessionControllerGetter.getJndiPath(AppleFruitMothBean.class));
+
+            return retVal;
+        }catch(NamingException ne)
+        {
+            System.out.println("Could not find " + AppleFruitMothBean.class.getSimpleName());
+            return null;
+        }
+    }
+    
     private static String getJndiPath(Class obj)
     {
         String retVal = SessionControllerGetter.JNDI_PATH + obj.getSimpleName();
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 112e0beb2e94818616710664781cfbe43efd701b..675ff41ac66a895f1d7de37769663bf3833c2f8f 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties
@@ -368,3 +368,17 @@ PLASMOVITI=Downy Mildew model
 startDateDayDegreeAccumulation=Start date for day degree accumulation
 PSILARTEMP=Psila rosae Temperature Model
 vipsLogicRole_6=Apple Fruit Moth Administrator
+observationSiteName=Observation site name
+newObservationSite=New observation site
+season=Season
+warningStatus_0=No forecast available
+warningStatus_1=Missing data
+warningStatus_2=No risk of infection
+warningStatus_3=Medium risk of infection
+warningStatus_4=High risk of infection
+warningStatus=Warning status
+thousandBerrySample=Thousand berry sample
+degreeOfParasitation=Degree of parasitation
+observationSitePoints=Observation site points
+newObservationSitePoint=New observation site point
+observationSitePointName=Observation site point name
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 446068367f3fad2c20394ad2b745d8f33612c6ce..720b40cb166f77c11ae8d232af768a264d7f0152 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties
@@ -368,3 +368,17 @@ PLASMOVITI=Downy Mildew model
 startDateDayDegreeAccumulation=Start date for day degree accumulation
 PSILARTEMP=Psila rosae Temperature Model
 vipsLogicRole_6=Apple Fruit Moth Administrator
+observationSiteName=Observation site name
+newObservationSite=New observation site
+season=Season
+warningStatus_0=No forecast available
+warningStatus_1=Missing data
+warningStatus_2=No risk of infection
+warningStatus_3=Medium risk of infection
+warningStatus_4=High risk of infection
+warningStatus=Warning status
+thousandBerrySample=Thousand berry sample
+degreeOfParasitation=Degree of parasitation
+observationSitePoints=Observation site pointsObservasjonsstedspunkter
+newObservationSitePoint=New observation site point
+observationSitePointName=Observation site point name
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 cd6fe371016291f0389afe6e24ec0af0568c56e5..c2f33db8cb4046d9a02cb25e8883b2aa2bd2936b 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties
@@ -367,3 +367,17 @@ PLASMOVITI=Downy Mildew model
 startDateDayDegreeAccumulation=Start date for day degree accumulation
 PSILARTEMP=Psila rosae Temperature Model
 vipsLogicRole_6=Apple Fruit Moth Administrator
+observationSiteName=Observation site name
+newObservationSite=New observation site
+season=Season
+warningStatus_0=No forecast available
+warningStatus_1=Missing data
+warningStatus_2=No risk of infection
+warningStatus_3=Medium risk of infection
+warningStatus_4=High risk of infection
+warningStatus=Warning status
+thousandBerrySample=Thousand berry sample
+degreeOfParasitation=Degree of parasitation
+observationSitePoints=Observation site points
+newObservationSitePoint=New observation site point
+observationSitePointName=Observation site point name
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 9beeae6af97292a9cdec0d1749821b940aec64fe..fa8187e333ae0d477fa6434e25e8a87da2bf6647 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties
@@ -368,3 +368,17 @@ PLASMOVITI=Vinbladskimmelmodell
 startDateDayDegreeAccumulation=Startdato for d\u00f8gngradakkumulasjon
 PSILARTEMP=Gulrotflue svermetidspunktmodell
 vipsLogicRole_6=Rogneb\u00e6rm\u00f8lladministrator
+observationSiteName=Navn p\u00e5 observasjonssted
+newObservationSite=Nytt observasjonssted
+season=Sesong
+warningStatus_0=Varsel beregnes ikke
+warningStatus_1=Data mangler
+warningStatus_2=Ingen infeksjonsrisiko
+warningStatus_3=Middels infeksjonsrisiko
+warningStatus_4=H\u00f8y infeksjonsrisiko
+warningStatus=Varselstatus
+thousandBerrySample=Tusenb\u00e6rpr\u00f8ve
+degreeOfParasitation=Parasitteringsgrad
+observationSitePoints=Observasjonsstedspunkter
+newObservationSitePoint=Nytt observasjonsstedspunkt
+observationSitePointName=Navn p\u00e5 observasjonsstedspunkt
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 51837f582aa2595e14d61778eb95935178ef8d8b..fb1d6b54773c95c5a6e55fbbc867fcd5d2bbb23d 100644
--- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
+++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties
@@ -368,3 +368,17 @@ PLASMOVITI=Downy Mildew model
 startDateDayDegreeAccumulation=Start date for day degree accumulation
 PSILARTEMP=Psila rosae Temperature Model
 vipsLogicRole_6=Apple Fruit Moth Administrator
+observationSiteName=Observation site name
+newObservationSite=New observation site
+season=Season
+warningStatus_0=No forecast available
+warningStatus_1=Missing data
+warningStatus_2=No risk of infection
+warningStatus_3=Medium risk of infection
+warningStatus_4=High risk of infection
+warningStatus=Warning status
+thousandBerrySample=Thousand berry sample
+degreeOfParasitation=Degree of parasitation
+observationSitePoints=Observation site points
+newObservationSitePoint=New observation site point
+observationSitePointName=Observation site point name
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index 90687a867d912c00bbc199ffc8f7b3667564c4ae..a9f7eeabf592a91a57a1a80012604da2834a404e 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -67,6 +67,10 @@
         <servlet-name>NotificationSubscriptionController</servlet-name>
         <servlet-class>no.nibio.vips.logic.controller.servlet.NotificationSubscriptionController</servlet-class>
     </servlet>
+    <servlet>
+        <servlet-name>AppleFruitMothController</servlet-name>
+        <servlet-class>no.nibio.vips.logic.modules.applefruitmoth.AppleFruitMothController</servlet-class>
+    </servlet>
     <servlet-mapping>
         <servlet-name>PointOfInterestController</servlet-name>
         <url-pattern>/poi/*</url-pattern>
@@ -119,6 +123,10 @@
         <servlet-name>NotificationSubscriptionController</servlet-name>
         <url-pattern>/user/notificationsubscription</url-pattern>
     </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>AppleFruitMothController</servlet-name>
+        <url-pattern>/applefruitmoth</url-pattern>
+    </servlet-mapping>
     <welcome-file-list>
         <welcome-file>index.html</welcome-file>
     </welcome-file-list>
diff --git a/src/main/webapp/templates/appleFruitMothStationForm.ftl b/src/main/webapp/templates/appleFruitMothStationForm.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..e61265b05a06b3ea8b0581d5d94890dca056159f
--- /dev/null
+++ b/src/main/webapp/templates/appleFruitMothStationForm.ftl
@@ -0,0 +1,110 @@
+<#--
+  Copyright (c) 2016 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/>.
+	
+--><#include "master.ftl">
+<#macro page_head>
+	<title>${observationSite.observationSiteName!i18nBundle.newObservationSite}</title>
+</#macro>
+<#macro custom_js>
+	<script src="/js/resourcebundle.js"></script>
+</#macro>
+<#macro page_contents>
+<h1>${observationSite.observationSiteName!i18nBundle.newObservationSite} ${currentSeason}</h1>
+<p><a href="/applefruitmoth" class="btn btn-default back" role="button">${i18nBundle.back}</a></p>
+<div class="singleBlockContainer">
+	
+	<div class="row">
+		<div class="col-md-6">
+			<#assign formId = "observationSiteForm">
+			<form id="${formId}" role="form" action="/applefruitmoth?action=observationSiteSubmit" method="POST">
+				<div class="form-group">
+				    <label for="observationSiteName">${i18nBundle.observationSiteName}</label>
+				    <input type="text" class="form-control" name="observationSiteName" placeholder="${i18nBundle.observationSiteName}" value="${observationSite.observationSiteName!""}" onblur="validateField(this);" />
+				    <span class="help-block" id="${formId}_observationSiteName_validation"></span>
+				  </div>
+				  <div class="form-group">
+				    <label for="currentSeason">${i18nBundle.season}</label>
+				    <select class="form-control" name="currentSeason" onchange="if(confirm('Really?')){window.location.href='/applefruitmoth?action=viewObservationSite&observationSiteId=${observationSite.observationSiteId}&currentSeason=' + this.options[this.options.selectedIndex].value;}">
+					<#list 2010..lastSeason as season>
+						<option value="${season}"<#if season == currentSeason> selected="selected"</#if>>${season}</option>
+					</#list>
+				     </select>
+				     <span class="help-block" id="${formId}_currentSeason_validation"></span>
+				  </div>
+				  <div class="form-group">
+					<label for="warningStatus">${i18nBundle.warningStatus}</label>
+					<select class="form-control" name="warningStatus">
+						<#list 0..4 as warningStatus>
+							<option value="${warningStatus}">${i18nBundle["warningStatus_" + warningStatus]}</option>
+						</#list>
+					</select>
+					<span class="help-block" id="${formId}_warningStatus_validation"></span>
+				  </div>
+				  <div class="form-group">
+					<label for="comments">${i18nBundle.remarks}</label>
+					<textarea class="form-control" placeholder="${i18nBundle.remarks}" name="remarks" rows="5" onblur="validateField(this);"><#if observationSiteSeasonCommonData??>${observationSiteSeasonCommonData.remarks}</#if></textarea>
+					<span class="help-block" id="${formId}_remarks_validation"></span>
+				  </div>
+				<div class="form-group">
+				    <label for="degreeOfParasitation">${i18nBundle.degreeOfParasitation}</label>
+				    <input type="number" class="form-control" name="degreeOfParasitation" placeholder="${i18nBundle.degreeOfParasitation}" value="<#if observationSiteSeasonCommonData??>${observationSiteSeasonCommonData.degreeOfParasitation!""}</#if>" onblur="validateField(this);" />
+				    <span class="help-block" id="${formId}_degreeOfParasitation_validation"></span>
+				</div>
+				<div class="form-group">
+				    <label for="thousandBerrySample">${i18nBundle.thousandBerrySample}</label>
+				    <input type="number" class="form-control" name="thousandBerrySample" placeholder="${i18nBundle.thousandBerrySample}" value="<#if observationSiteSeasonCommonData??>${observationSiteSeasonCommonData.thousandBerrySample!""}</#if>" onblur="validateField(this);" />
+				    <span class="help-block" id="${formId}_thousandBerrySample_validation"></span>
+				</div>
+				<h2>${i18nBundle.observationSitePoints}</h2>
+				<#if observationSitePoints??>
+					<#list observationSitePoints as observationSitePoint>
+					<fieldset>
+						<legend>${observationSitePoint.pointName}</legend>
+						<div class="form-group">
+						    <label for="observationSitePointName_${observationSitePoint.observationSitePointId}">${i18nBundle.observationSitePointName}</label>
+						    <input type="text" class="form-control" name="observationSitePointName_${observationSitePoint.observationSitePointId}" placeholder="${i18nBundle.observationSitePointName}" value="${observationSitePoint.pointName!""}" />
+						  </div>
+						<div class="form-group">
+							<label for="observationSitePoint_description_${observationSitePoint.observationSitePointId}">${i18nBundle.description}</label>
+							<textarea class="form-control" placeholder="${i18nBundle.description}" name="observationSitePoint_description_${observationSitePoint.observationSitePointId}" rows="3"></textarea>
+						</div>
+					
+					</fieldset>
+					</#list>
+					
+				</#if>
+				<fieldset>
+					<legend>${i18nBundle.newObservationSitePoint}</legend>
+					<div class="form-group">
+						    <label for="observationSitePointName_new">${i18nBundle.observationSitePointName}</label>
+						    <input type="text" class="form-control" name="observationSitePointName_new" placeholder="${i18nBundle.observationSitePointName}" value="" />
+						  </div>
+					 <div class="form-group">
+						<label for="observationSitePoint_description_new">${i18nBundle.description}</label>
+						<textarea class="form-control" placeholder="${i18nBundle.description}" name="observationSitePoint_description_new" rows="3"></textarea>
+					</div>
+				
+				</fieldset>
+			</form>
+		</div>
+		<div class="col-md-6">
+		Kart
+		</div>
+	</div>
+</div>	
+</#macro>
+<@page_html/>
diff --git a/src/main/webapp/templates/appleFruitMothStationList.ftl b/src/main/webapp/templates/appleFruitMothStationList.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..97e4a6fb370a3ca2d068a1d0d3c0fd57700b88dd
--- /dev/null
+++ b/src/main/webapp/templates/appleFruitMothStationList.ftl
@@ -0,0 +1,34 @@
+<#--
+  Copyright (c) 2016 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/>.
+	
+--><#include "master.ftl">
+<#macro page_head>
+	
+</#macro>
+<#macro custom_js>
+	<script src="/js/resourcebundle.js"></script>
+</#macro>
+<#macro page_contents>
+<div class="singleBlockContainer">
+	<ul>
+	<#list observationSites as observationSite>
+	<li><a href="/applefruitmoth?action=viewObservationSite&observationSiteId=${observationSite.observationSiteId}">${observationSite.observationSiteName}</a></li>
+	</#list>
+	</ul>
+</div>	
+</#macro>
+<@page_html/>