diff --git a/CHANGELOG b/CHANGELOG
index 3c6066108aeb4bdc95716999983315a303d2e8fd..03fe24f31ed75a22d0b34ce8f3505942e043696b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -82,12 +82,17 @@ minerva (12.0.0~alpha.0) unstable; urgency=medium
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Wed, 21 Feb 2018 12:00:00 +0200
 
+minerva (11.1.0) stable; urgency=high
+  * User can provide Google Maps API key that must be registered in google
+    cloud account
+
+ -- Piotr Gawron <piotr.gawron@uni.lu>  Mon, 14 May 2018 9:00:00 +0200
+
 minerva (11.0.10) stable; urgency=medium
   * Bug fix: link from overview image to search result was broken
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Wed, 16 Apr 2018 15:00:00 +0200
 
-
 minerva (11.0.9) stable; urgency=medium
   * Bug fix: some comment couldn't be loaded
   * Bug fix: when adding comment it didn't appear on map immediately
diff --git a/frontend-js/src/main/js/ConfigurationType.js b/frontend-js/src/main/js/ConfigurationType.js
index 1ce31b07fc58d9ba2f6542d09475783019a16062..183411fcea0dadee718eb8984c9874866e201534 100644
--- a/frontend-js/src/main/js/ConfigurationType.js
+++ b/frontend-js/src/main/js/ConfigurationType.js
@@ -3,6 +3,7 @@
 var ConfigurationType = {
   DEFAULT_MAP: "DEFAULT_MAP",
   GOOGLE_ANALYTICS_IDENTIFIER: "GOOGLE_ANALYTICS_IDENTIFIER",
+  GOOGLE_MAPS_API_KEY: "GOOGLE_MAPS_API_KEY",
   LOGO_IMG: "LOGO_IMG",
   LOGO_LINK: "LOGO_LINK",
   LOGO_TEXT: "LOGO_TEXT",
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 4ff0fc4f086e3d63e29ff7cb22a449573e513db7..fc653b7e7f7cc06712298959a0f01ac76e3794b6 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -1742,7 +1742,8 @@ ServerConnector.updateOverlay = function (overlay) {
       description: overlay.getDescription(),
       creator: overlay.getCreator(),
       publicOverlay: overlay.getPublicOverlay(),
-      defaultOverlay: overlay.isDefaultOverlay()
+      defaultOverlay: overlay.isDefaultOverlay(),
+      googleLicenseConsent : overlay.isGoogleLicenseConsent()
     }
   };
   return self.sendPatchRequest(self.updateOverlayUrl(queryParams), filterParams);
diff --git a/frontend-js/src/main/js/gui/Panel.js b/frontend-js/src/main/js/gui/Panel.js
index d4a1129b38d61d57078b1bab03267e0dcb85536f..3a6c1ca96a6e31e140312c77e58b3f9c3c3a1259 100644
--- a/frontend-js/src/main/js/gui/Panel.js
+++ b/frontend-js/src/main/js/gui/Panel.js
@@ -166,6 +166,8 @@ Panel.prototype.assignDialogOptions = function (div, params) {
         dialog.dialog('option', 'dialogClass', params[key]);
       } else if (key === "title") {
         dialog.dialog('option', 'title', params[key]);
+      } else if (key === "width") {
+        dialog.dialog('option', 'width', params[key]);
       } else {
         throw new Error("Unknown dialog param: " + key + " - " + params[key]);
       }
diff --git a/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js b/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js
index aac93a0effb65c153f3eb5812d4ec0f8067b078a..ecbe4037d7c18ef3c5d7be97f9d864cfebd15332 100644
--- a/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js
@@ -316,4 +316,12 @@ LeftPanel.prototype.destroy = function () {
   return Promise.all(promises);
 };
 
+LeftPanel.prototype.setGoogleLicenseConsentRequired = function (value) {
+  this._googleLicenseConsentRequired = value;
+};
+
+LeftPanel.prototype.isGoogleLicenseConsentRequired = function () {
+  return this._googleLicenseConsentRequired;
+};
+
 module.exports = LeftPanel;
diff --git a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
index 5e6380700e1799568a0a325a7525c6bcf9cd8be7..9fe91b1abab770bfffe178b339656f68d29be90f 100644
--- a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
@@ -141,8 +141,6 @@ OverlayPanel.prototype._createOverlayPanelGui = function () {
     content: "Add overlay"
   });
   centerTag.appendChild(addOverlayButton);
-
-
   this.setControlElement(PanelControlElementType.OVERLAY_ADD_OVERLAY_BUTTON, addOverlayButton);
 };
 
@@ -183,7 +181,7 @@ OverlayPanel.prototype.createTableHeader = function (edit) {
   return result;
 };
 
-OverlayPanel.prototype.createOverlayRow = function (overlay, checked) {
+OverlayPanel.prototype.createOverlayRow = function (overlay, checked, disabled) {
   var self = this;
   var guiUtils = self.getGuiUtils();
   var result = document.createElement("tr");
@@ -204,6 +202,7 @@ OverlayPanel.prototype.createOverlayRow = function (overlay, checked) {
       data: overlay.getId()
     });
     checkbox.checked = checked;
+    $(checkbox).prop("disabled", disabled);
     viewTd.appendChild(checkbox);
   } else {
     var img = guiUtils.createIcon("icons/search.png");
@@ -285,12 +284,21 @@ OverlayPanel.prototype.openEditOverlayDialog = function (overlay) {
   row = guiUtils.createTableRow([guiUtils.createLabel("Description: "), descriptionInput]);
   content.appendChild(row);
 
+  var consentCheckbox = document.createElement("input");
+  consentCheckbox.type = "checkbox";
+  consentCheckbox.checked = overlay.isGoogleLicenseConsent();
+  row = guiUtils.createTableRow([guiUtils.createLabel("I am aware that this map is displayed under the terms of the <a href='https://cloud.google.com/maps-platform/terms/' target='_blank'>license of Google Maps Platform</a> and I agree to these terms. " +
+    "In particular, I warrant that this dataset does not contain Protected Health Information (as defined in and subject to HIPAA). "), consentCheckbox]);
+  content.appendChild(row);
+
   var buttons = [{
     text: "SAVE",
     click: function () {
       var windowSelf = this;
       overlay.setName(nameInput.value);
       overlay.setDescription(descriptionInput.value);
+      overlay.setGoogleLicenseConsent(consentCheckbox.checked);
+
       return ServerConnector.updateOverlay(overlay).then(function () {
         return self.refresh();
       }).then(function () {
@@ -318,6 +326,7 @@ OverlayPanel.prototype.openEditOverlayDialog = function (overlay) {
     }
   }];
   self.openDialog(content, {
+    width: "600px",
     id: overlay.getId(),
     buttons: buttons,
     title: "Data overlay: " + overlay.getName(),
@@ -377,7 +386,7 @@ OverlayPanel.prototype.refresh = function (showDefault) {
     table.appendChild(body);
     for (i = 0; i < generalOverlays.length; i++) {
       overlay = generalOverlays[i];
-      body.appendChild(self.createOverlayRow(overlay, selectedOverlay[overlay.getId()]));
+      body.appendChild(self.createOverlayRow(overlay, selectedOverlay[overlay.getId()], false));
     }
 
     var title = self.getControlElement(PanelControlElementType.OVERLAY_CUSTOM_OVERLAY_TITLE);
@@ -406,12 +415,16 @@ OverlayPanel.prototype.refresh = function (showDefault) {
         }
       }).DataTable();
       var data = [];
+      self.setGoogleLicenseConsentRequired(false);
       for (i = 0; i < customOverlays.length; i++) {
         overlay = customOverlays[i];
         if (showDefault && overlay.isDefaultOverlay()) {
           selectedOverlay[overlay.getId()] = true;
         }
-        data.push(self.overlayToDataRow(overlay, selectedOverlay[overlay.getId()]));
+        data.push(self.overlayToDataRow(overlay, selectedOverlay[overlay.getId()], !overlay.isGoogleLicenseConsent()));
+        if (!overlay.isGoogleLicenseConsent()) {
+          self.setGoogleLicenseConsentRequired(true);
+        }
       }
       table.clear().rows.add(data).draw();
 
@@ -532,4 +545,10 @@ OverlayPanel.prototype.destroy = function () {
   }
 };
 
+OverlayPanel.prototype.setGoogleLicenseConsentRequired = function (value) {
+  var leftPanel = this.getParent();
+  if (leftPanel !== undefined) {
+    leftPanel.setGoogleLicenseConsentRequired(value);
+  }
+};
 module.exports = OverlayPanel;
diff --git a/frontend-js/src/main/js/map/data/DataOverlay.js b/frontend-js/src/main/js/map/data/DataOverlay.js
index a859fe054c2e50dd300201a31b05280bcecc4803..a4d6f2749d3c3412f3f65a79f7334bbf25e3a9bd 100644
--- a/frontend-js/src/main/js/map/data/DataOverlay.js
+++ b/frontend-js/src/main/js/map/data/DataOverlay.js
@@ -26,6 +26,7 @@ function DataOverlay(overlayId, name) {
     this.setFilename(object.filename);
     this.setPublicOverlay(object.publicOverlay);
     this.setDefaultOverlay(object.defaultOverlay);
+    this.setGoogleLicenseConsent(object.googleLicenseConsent);
     this.setInputDataAvailable(object.inputDataAvailable);
     this.setType(object.type);
     if (!this.getInputDataAvailable()) {
@@ -241,6 +242,14 @@ DataOverlay.prototype.setType = function (type) {
   this._type = type;
 };
 
+DataOverlay.prototype.setGoogleLicenseConsent = function(value) {
+  this._googleLicenseConsent = value;
+};
+
+DataOverlay.prototype.isGoogleLicenseConsent = function() {
+  return this._googleLicenseConsent;
+};
+
 DataOverlay.prototype.update = function (overlay) {
   this.setName(overlay.getName());
   this.setDescription(overlay.getDescription());
diff --git a/frontend-js/src/main/js/minerva.js b/frontend-js/src/main/js/minerva.js
index 0cffc5c39049005e18b8ec5debaeaf7a81ccece0..83fa8dd4637dab7d6a685454f130137012b2895c 100644
--- a/frontend-js/src/main/js/minerva.js
+++ b/frontend-js/src/main/js/minerva.js
@@ -246,12 +246,13 @@ function create(params) {
   params.getElement().innerHTML = "<div style='vertical-align:middle;display:table-cell;text-align: center'>"
     + "<img src='resources/images/icons/ajax-loader.gif'/>" + "</div>";
 
-  // make sure that we are logged in
   // make sure that we are logged in
   return ServerConnector.createSession().then(function () {
     return ServerConnector.getConfiguration();
   }).then(function (configuration) {
     params.setConfiguration(configuration);
+    return functions.loadScript("https://maps.google.com/maps/api/js?libraries=drawing&v=3.26&key=" + configuration.getOption(ConfigurationType.GOOGLE_MAPS_API_KEY));
+  }).then(function () {
     return getProject(params);
   }).then(function (project) {
     if (project === null) {
@@ -353,6 +354,9 @@ function create(params) {
     }
     return Promise.all(promises);
   }).then(function () {
+    if (leftPanel.isGoogleLicenseConsentRequired()) {
+      GuiConnector.alert("Some data overlays doesn't have consent to the terms of the <a href='https://cloud.google.com/maps-platform/terms/' target='_blank'>license of Google Maps Platform</a>. To be able to visualize them you must edit data overlay. ")
+    }
     var result = {
       destroy: function () {
         return leftPanel.destroy().then(function () {
@@ -538,6 +542,8 @@ function createExport(params) {
   // make sure that we are logged in
   return ServerConnector.getConfiguration().then(function (configuration) {
     params.setConfiguration(configuration);
+    return functions.loadScript("https://maps.google.com/maps/api/js?libraries=drawing&v=3.26&key=" + configuration.getOption(ConfigurationType.GOOGLE_MAPS_API_KEY));
+  }).then(function () {
     return getProject(params);
   }).then(function (project) {
     params.setProject(project);
@@ -568,6 +574,8 @@ function createAdmin(params) {
     return ServerConnector.getConfiguration();
   }).then(function (configuration) {
     params.setConfiguration(configuration);
+    return functions.loadScript("https://maps.google.com/maps/api/js?libraries=drawing&v=3.26&key=" + configuration.getOption(ConfigurationType.GOOGLE_MAPS_API_KEY));
+  }).then(function () {
     result = new Admin(params);
     return createFooter();
   }).then(function (footer) {
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java b/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java
index 78add52b8436ccf274e2d53bc497f799b95d1645..6a4efe053f62162f80c2ac17f78eea7f15b336c1 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java
@@ -94,6 +94,9 @@ public class Layout implements Serializable {
    */
   private boolean hierarchicalView = false;
 
+  @Column(name="google_license_consent")
+  private boolean                     googleLicenseConsent = false;
+
   /**
    * If overlay contain hierarchical view then it might be fixed on some specific
    * level. This parameter defines the level at which it's fixed or contains null
@@ -487,4 +490,12 @@ public class Layout implements Serializable {
     this.orderIndex = orderIndex;
   }
 
+  public boolean isGoogleLicenseConsent() {
+    return googleLicenseConsent;
+  }
+
+  public void setGoogleLicenseConsent(boolean googleLicenseConsent) {
+    this.googleLicenseConsent = googleLicenseConsent;
+  }
+
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
index a9ce9dd9ea74fc3047c5d1323fffd8f9fac070ec..27b2aceee9fb34686cb5d703814b1a9551e3c427 100644
--- a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
+++ b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
@@ -188,6 +188,12 @@ public enum ConfigurationElementType {
   SHOW_REACTION_TYPE("Show reaction type when browsing map", "true",
       ConfigurationElementEditType.BOOLEAN, false, ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
 
+  GOOGLE_MAPS_API_KEY("By providing this Google Maps Platform API key I declare that I am aware that "
+      + "I am a Customer of the Google Maps Platform and I agree to the terms of the <a href=\"https://cloud.google.com/maps-platform/terms/\"  target='_blank'>license of Google Maps Platform</a>." +
+      "In particular, I warrant that neither any of the maps nor publicly available data overlays "
+      + "(\"General overlays\") on this MINERVA server contain Protected Health Information (as defined in and subject to HIPAA).",
+      "", ConfigurationElementEditType.STRING, false, ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
+
   ;
 
   /**
@@ -211,7 +217,7 @@ public enum ConfigurationElementType {
 
   /**
    * Default constructor.
-   * 
+   *
    * @param commonName
    *          common name used for this parameter
    * @param editType
diff --git a/persist/src/db/11.1.0/fix_db_20180509.sql b/persist/src/db/11.1.0/fix_db_20180509.sql
new file mode 100644
index 0000000000000000000000000000000000000000..7b90e53299d30f2657a70e2816afaa6de66c81bc
--- /dev/null
+++ b/persist/src/db/11.1.0/fix_db_20180509.sql
@@ -0,0 +1 @@
+alter table layout add column google_license_consent boolean default false;
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java
index ae0568257d0e2ad77737f8a9a61c54d984f63bcb..df87863ca25954c20b43aea180103f7b0c1e9fb4 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java
@@ -214,6 +214,8 @@ public class OverlayRestImpl extends BaseRestImpl {
           layout.setPublicLayout(parseBoolean(value));
         } else if (key.equalsIgnoreCase("defaultOverlay")) {
           layout.setDefaultOverlay(parseBoolean(value));
+        } else if (key.equalsIgnoreCase("googleLicenseConsent")) {
+          layout.setGoogleLicenseConsent((Boolean) overlayData.get("googleLicenseConsent"));
         } else if (key.equalsIgnoreCase("creator")) {
           if ("".equals(value)) {
             layout.setCreator(null);
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java b/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
index 27a911d583bb0f5e92144e5280bd4571e29fe088..24506ac69c2b717b8013c78449c4ae8a95e64515 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
@@ -1,1007 +1,1008 @@
-package lcsb.mapviewer.services.impl;
-
-import java.awt.Color;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.PostConstruct;
-import javax.mail.MessagingException;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.log4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-
-import lcsb.mapviewer.annotation.services.MiriamConnector;
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.commands.ColorModelCommand;
-import lcsb.mapviewer.commands.CommandExecutionException;
-import lcsb.mapviewer.commands.CopyCommand;
-import lcsb.mapviewer.common.IProgressUpdater;
-import lcsb.mapviewer.common.Pair;
-import lcsb.mapviewer.common.TextFileUtils;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.InvalidStateException;
-import lcsb.mapviewer.converter.graphics.MapGenerator;
-import lcsb.mapviewer.converter.graphics.MapGenerator.MapGeneratorParams;
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.cache.UploadedFileEntry;
-import lcsb.mapviewer.model.log.LogType;
-import lcsb.mapviewer.model.map.MiriamData;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.layout.GeneVariation;
-import lcsb.mapviewer.model.map.layout.GeneVariationColorSchema;
-import lcsb.mapviewer.model.map.layout.GenericColorSchema;
-import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
-import lcsb.mapviewer.model.map.layout.Layout;
-import lcsb.mapviewer.model.map.layout.LayoutStatus;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
-import lcsb.mapviewer.model.map.reaction.Reaction;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.user.ObjectPrivilege;
-import lcsb.mapviewer.model.user.PrivilegeType;
-import lcsb.mapviewer.model.user.User;
-import lcsb.mapviewer.persist.DbUtils;
-import lcsb.mapviewer.persist.dao.map.LayoutDao;
-import lcsb.mapviewer.services.SecurityException;
-import lcsb.mapviewer.services.interfaces.IConfigurationService;
-import lcsb.mapviewer.services.interfaces.ILayoutService;
-import lcsb.mapviewer.services.interfaces.ILogService;
-import lcsb.mapviewer.services.interfaces.ILogService.LogParams;
-import lcsb.mapviewer.services.interfaces.IUserService;
-import lcsb.mapviewer.services.search.layout.FullLayoutAliasView;
-import lcsb.mapviewer.services.search.layout.FullLayoutAliasViewFactory;
-import lcsb.mapviewer.services.search.layout.FullLayoutReactionView;
-import lcsb.mapviewer.services.search.layout.FullLayoutReactionViewFactory;
-import lcsb.mapviewer.services.search.layout.LightLayoutAliasView;
-import lcsb.mapviewer.services.search.layout.LightLayoutAliasViewFactory;
-import lcsb.mapviewer.services.search.layout.LightLayoutReactionView;
-import lcsb.mapviewer.services.search.layout.LightLayoutReactionViewFactory;
-import lcsb.mapviewer.services.utils.ColorSchemaReader;
-import lcsb.mapviewer.services.utils.EmailSender;
-import lcsb.mapviewer.services.utils.data.ColorSchemaColumn;
-
-/**
- * Implementation of the layout service.
- * 
- * @author Piotr Gawron
- * 
- */
-@Transactional(value = "txManager")
-public class LayoutService implements ILayoutService {
-
-  /**
-   * Default class logger.
-   */
-  private Logger logger = Logger.getLogger(LayoutService.class);
-
-  /**
-   * Layout data access object.
-   */
-  @Autowired
-  private LayoutDao layoutDao;
-
-  /**
-   * Service that manages and gives access to user information.
-   */
-  @Autowired
-  private IUserService userService;
-
-  /**
-   * Service used to access logs.
-   *
-   * @see ILogService
-   */
-  @Autowired
-  private ILogService logService;
-
-  /**
-   * Service that manages and gives access to configuration parameters.
-   */
-  @Autowired
-  private IConfigurationService configurationService;
-
-  /**
-   * Utility class that helps to manage the sessions in custom multi-threaded
-   * implementation.
-   */
-  @Autowired
-  private DbUtils dbUtils;
-
-  /**
-   * Object that sends emails.
-   */
-  private EmailSender emailSender;
-
-  /**
-   * Method called after spring initialized all interfaces.
-   */
-  @PostConstruct
-  public void springInit() {
-    emailSender = new EmailSender(configurationService);
-  }
-
-  @Override
-  public boolean userCanAddLayout(Model model, User user) {
-    // if we don't have privileges to view the object then we cannot add layouts
-    if (!userService.userHasPrivilege(user, PrivilegeType.VIEW_PROJECT, model.getProject())) {
-      return false;
-    }
-    long count = getAvailableCustomLayoutsNumber(user);
-    return count > 0;
-  }
-
-  @Override
-  public long getAvailableCustomLayoutsNumber(User user) {
-    long level = userService.getUserPrivilegeLevel(user, PrivilegeType.CUSTOM_LAYOUTS);
-    long layouts = layoutDao.getCountByUser(user);
-    return level - layouts;
-
-  }
-
-  @Override
-  public boolean userCanRemoveLayout(Layout layout, User user) {
-    User creator = layout.getCreator();
-    Project project = layout.getModel().getProject();
-    if (creator == null) {
-      return userService.userHasPrivilege(user, PrivilegeType.LAYOUT_MANAGEMENT, project);
-    } else {
-      return creator.getId().equals(user.getId())
-          || userService.userHasPrivilege(user, PrivilegeType.LAYOUT_MANAGEMENT, project);
-    }
-  }
-
-  private boolean userCanViewOverlay(Layout overlay, User user) {
-    if (overlay.isPublicLayout()) {
-      return true;
-    }
-    if (overlay.getCreator() == null) {
-      return true;
-    }
-    if (overlay.getCreator().getLogin().equals(user.getLogin())) {
-      return true;
-    }
-
-    if (userService.userHasPrivilege(user, PrivilegeType.LAYOUT_VIEW, overlay)) {
-      return true;
-    }
-    if (userService.userHasPrivilege(user, PrivilegeType.LAYOUT_MANAGEMENT, overlay.getModel().getProject())) {
-      return true;
-    }
-    return false;
-  }
-
-  @Override
-  public void removeLayout(Layout layout, final String homeDir) throws IOException {
-    final String dir;
-    if (homeDir != null) {
-      if (layout.getModel().getProject().getDirectory() != null) {
-        dir = homeDir + "/../map_images/" + layout.getModel().getProject().getDirectory() + "/";
-      } else {
-        dir = homeDir + "/../map_images/";
-      }
-    } else {
-      dir = null;
-    }
-
-    String projectId = layout.getModel().getProject().getProjectId();
-    final String email;
-    User user = layout.getCreator();
-    if (user != null) {
-      email = user.getEmail();
-    } else {
-      email = null;
-    }
-
-    layout.getModel().removeLayout(layout);
-    layoutDao.delete(layout);
-
-    LogParams params = new LogParams().object(layout).type(LogType.LAYOUT_REMOVED);
-    logService.log(params);
-
-    if (email != null) {
-      Thread sendEmailThread = new Thread(new Runnable() {
-        @Override
-        public void run() {
-          try {
-            sendSuccesfullRemoveEmail(projectId, layout.getTitle(), email);
-          } catch (MessagingException e) {
-            logger.error(e);
-          }
-        }
-      });
-      sendEmailThread.start();
-    }
-    Thread removeFilesThread = new Thread(new Runnable() {
-      @Override
-      public void run() {
-        MapGenerator generator = new MapGenerator();
-        try {
-          generator.removeLayout(layout, dir);
-        } catch (IOException e) {
-          logger.error(e);
-        }
-
-      }
-    });
-    removeFilesThread.start();
-  }
-
-  @Override
-  public void updateLayout(Layout layout) {
-    layoutDao.update(layout);
-  }
-
-  @Override
-  public void addViewPrivilegeToLayout(Layout layout, User user) {
-    ObjectPrivilege privilege = new ObjectPrivilege();
-    privilege.setIdObject(layout.getId());
-    privilege.setLevel(1);
-    privilege.setType(PrivilegeType.LAYOUT_VIEW);
-    privilege.setUser(user);
-    userService.setUserPrivilege(user, privilege);
-  }
-
-  @Override
-  public void dropViewPrivilegeFromLayout(Layout layout, User user) {
-    ObjectPrivilege privilege = new ObjectPrivilege();
-    privilege.setIdObject(layout.getId());
-    privilege.setLevel(0);
-    privilege.setType(PrivilegeType.LAYOUT_VIEW);
-    privilege.setUser(user);
-    userService.setUserPrivilege(user, privilege);
-  }
-
-  @Override
-  public Layout createLayoutWithImages(final CreateLayoutParams params)
-      throws IOException, InvalidColorSchemaException, CommandExecutionException {
-    ColorSchemaReader reader = new ColorSchemaReader();
-    final Collection<ColorSchema> schemas = reader.readColorSchema(params.getColorInputStream(),
-        TextFileUtils.getHeaderParametersFromFile(params.getColorInputStream()));
-    final Model colorModel = new CopyCommand(params.getModel()).execute();
-    new ColorModelCommand(params.getModel(), schemas, userService.getColorExtractorForUser(params.getUser())).execute();
-    String[] tmp = params.getDirectory().split("[\\\\/]");
-    String simpleDir = tmp[tmp.length - 1];
-
-    layoutDao.flush();
-
-    boolean customSession = false;
-    if (params.isAsync()) {
-      customSession = !dbUtils.isCustomSessionForCurrentThread();
-      if (customSession) {
-        dbUtils.createSessionForCurrentThread();
-      }
-    }
-    final Map<Model, Integer> layoutIdByModel = new HashMap<>();
-
-    Layout topLayout = new Layout(params.getName(), simpleDir, false);
-    if (params.getUser() == null) {
-      topLayout.setPublicLayout(true);
-    } else {
-      topLayout.setPublicLayout(false);
-    }
-    topLayout.setStatus(LayoutStatus.NA);
-    topLayout.setProgress(0.0);
-    UploadedFileEntry fileEntry = new UploadedFileEntry();
-    fileEntry.setFileContent(IOUtils.toByteArray(params.getColorInputStream()));
-    fileEntry.setOriginalFileName(params.getLayoutFileName());
-    fileEntry.setLength(fileEntry.getFileContent().length);
-    fileEntry.setOwner(params.getUser());
-    topLayout.setInputData(fileEntry);
-    topLayout.setDescription(params.getDescription());
-    params.getModel().addLayout(topLayout);
-    topLayout.setCreator(params.getUser());
-    layoutDao.add(topLayout);
-    topLayout.setDirectory(simpleDir + topLayout.getId());
-
-    layoutDao.update(topLayout);
-
-    layoutIdByModel.put(colorModel, topLayout.getId());
-
-    for (ModelSubmodelConnection connection : params.getModel().getSubmodelConnections()) {
-      Layout layout = new Layout(params.getName(), simpleDir, false);
-      layout.setStatus(LayoutStatus.NA);
-      layout.setProgress(0.0);
-      connection.getSubmodel().getModel().addLayout(layout);
-      layout.setCreator(params.getUser());
-      layout.setPublicLayout(false);
-      topLayout.addLayout(layout);
-      layoutDao.add(layout);
-      layout.setDirectory(simpleDir + layout.getId());
-
-      layoutDao.update(layout);
-
-      layoutIdByModel.put(colorModel.getSubmodelByConnectionName(connection.getName()), layout.getId());
-    }
-
-    if (params.isAsync()) {
-      if (customSession) {
-        dbUtils.closeSessionForCurrentThread();
-      } else {
-        layoutDao.commit();
-      }
-    }
-    final int layoutId = layoutIdByModel.get(colorModel);
-
-    Thread computations = new Thread(new Runnable() {
-      @Override
-      public void run() {
-        if (params.isAsync()) {
-          // open transaction for this thread
-          dbUtils.createSessionForCurrentThread();
-        }
-
-        try {
-          MapGenerator generator = new MapGenerator();
-          final int models = layoutIdByModel.entrySet().size();
-
-          int count = 0;
-          for (Model m : layoutIdByModel.keySet()) {
-            final int counted = count;
-            int id = layoutIdByModel.get(m);
-            MapGeneratorParams imgParams = generator.new MapGeneratorParams().model(m)
-                .directory(params.getDirectory() + id).updater(new IProgressUpdater() {
-                  private int lastProgress = -1;
-
-                  @Override
-                  public void setProgress(double progress) {
-                    progress = progress / ((double) models) + ((double) counted * MAX_PROGRESS) / ((double) models);
-                    if (((int) progress) != lastProgress) {
-                      Layout layout = layoutDao.getById(layoutId);
-                      lastProgress = (int) progress;
-                      layout.setProgress(progress);
-                      layout.setStatus(LayoutStatus.GENERATING);
-                      layoutDao.update(layout);
-                      if (params.isAsync()) {
-                        layoutDao.commit();
-                      }
-                    }
-                  }
-                });
-            imgParams.sbgn(params.getModel().getProject().isSbgnFormat());
-            generator.generateMapImages(imgParams);
-            count++;
-          }
-          Layout layout = layoutDao.getById(layoutId);
-          layout.setProgress(IProgressUpdater.MAX_PROGRESS);
-          layout.setStatus(LayoutStatus.OK);
-          layoutDao.update(layout);
-          if (params.isAsync()) {
-            layoutDao.commit();
-          }
-
-          try {
-            sendSuccessfullGenerationEmail(params, schemas);
-          } catch (MessagingException e) {
-            logger.error("Problem with sending email", e);
-          }
-          logService
-              .log(new LogParams().object(layout).description("Created successfully.").type(LogType.LAYOUT_CREATED));
-        } catch (Exception e) {
-          logger.error("Problem with creating layout", e);
-
-          Layout layout = layoutDao.getById(layoutId);
-          layout.setProgress(IProgressUpdater.MAX_PROGRESS);
-          layout.setStatus(LayoutStatus.FAILURE);
-          layoutDao.update(layout);
-
-          try {
-            emailSender.sendEmail("MapViewer status", "There was a problem with generating layout " + params.getName()
-                + ". Contact administrator to solve this issue.", params.getUser());
-          } catch (MessagingException e1) {
-            logger.error("Problem with sending email", e1);
-          }
-          logService
-              .log(new LogParams().object(layout).description("Problem during creation.").type(LogType.LAYOUT_CREATED));
-        }
-        if (params.isAsync()) {
-          // close the transaction for this thread
-          dbUtils.closeSessionForCurrentThread();
-        }
-      }
-    });
-
-    if (params.isAsync()) {
-      computations.start();
-    } else {
-      computations.run();
-    }
-    return topLayout;
-  }
-
-  @Override
-  public Layout createLayout(final CreateLayoutParams params) throws IOException, InvalidColorSchemaException {
-    ColorSchemaReader reader = new ColorSchemaReader();
-    final Collection<ColorSchema> schemas = reader.readColorSchema(params.getColorInputStream(),
-        TextFileUtils.getHeaderParametersFromFile(params.getColorInputStream()));
-
-    // check if we can color our model using this schema,
-    // if not then exception will be thrown and passed up
-    try {
-      Model copy = new CopyCommand(params.getModel()).execute();
-      new ColorModelCommand(copy, schemas, userService.getColorExtractorForUser(params.getUser())).execute();
-    } catch (CommandExecutionException e) {
-      throw new InvalidColorSchemaException(e);
-    }
-
-    String[] tmp = params.getDirectory().split("[\\\\/]");
-    String simpleDir = tmp[tmp.length - 1];
-
-    layoutDao.flush();
-
-    Layout topLayout = new Layout(params.getName(), simpleDir, false);
-    if (params.getUser() == null) {
-      topLayout.setPublicLayout(true);
-    } else {
-      topLayout.setPublicLayout(false);
-    }
-    topLayout.setStatus(LayoutStatus.OK);
-    topLayout.setProgress(0.0);
-    UploadedFileEntry fileEntry = new UploadedFileEntry();
-    fileEntry.setFileContent(IOUtils.toByteArray(params.getColorInputStream()));
-    fileEntry.setOriginalFileName(params.getLayoutFileName());
-    fileEntry.setLength(fileEntry.getFileContent().length);
-    fileEntry.setOwner(params.getUser());
-    topLayout.setInputData(fileEntry);
-    topLayout.setDescription(params.getDescription());
-    params.getModel().addLayout(topLayout);
-    topLayout.setCreator(params.getUser());
-    layoutDao.add(topLayout);
-    topLayout.setDirectory(simpleDir + topLayout.getId());
-
-    layoutDao.update(topLayout);
-
-    for (ModelSubmodelConnection connection : params.getModel().getSubmodelConnections()) {
-      Layout layout = new Layout(params.getName(), simpleDir, false);
-      layout.setStatus(LayoutStatus.OK);
-      layout.setProgress(0.0);
-      connection.getSubmodel().getModel().addLayout(layout);
-      layout.setCreator(params.getUser());
-      layout.setPublicLayout(false);
-      topLayout.addLayout(layout);
-      layoutDao.add(layout);
-      layout.setDirectory(simpleDir + layout.getId());
-
-      layoutDao.update(layout);
-    }
-
-    Thread computations = new Thread(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          // open transaction for this thread
-          dbUtils.createSessionForCurrentThread();
-          sendSuccessfullGenerationEmail(params, schemas);
-        } catch (MessagingException e) {
-          logger.error("Problem with sending email", e);
-        } finally {
-          dbUtils.closeSessionForCurrentThread();
-        }
-      }
-    });
-
-    LogParams logParams = new LogParams().object(topLayout).description("Created successfully.")
-        .type(LogType.LAYOUT_CREATED);
-    logService.log(logParams);
-
-    computations.start();
-    return topLayout;
-  }
-
-  /**
-   * @return the configurationService
-   * @see #configurationService
-   */
-  public IConfigurationService getConfigurationService() {
-    return configurationService;
-  }
-
-  /**
-   * @param configurationService
-   *          the configurationService to set
-   * @see #configurationService
-   */
-  public void setConfigurationService(IConfigurationService configurationService) {
-    this.configurationService = configurationService;
-  }
-
-  /**
-   * @return the dbUtils
-   * @see #dbUtils
-   */
-  public DbUtils getDbUtils() {
-    return dbUtils;
-  }
-
-  /**
-   * @param dbUtils
-   *          the dbUtils to set
-   * @see #dbUtils
-   */
-  public void setDbUtils(DbUtils dbUtils) {
-    this.dbUtils = dbUtils;
-  }
-
-  /**
-   * @return the userService
-   * @see #userService
-   */
-  public IUserService getUserService() {
-    return userService;
-  }
-
-  /**
-   * @param userService
-   *          the userService to set
-   * @see #userService
-   */
-  public void setUserService(IUserService userService) {
-    this.userService = userService;
-  }
-
-  /**
-   * Sends notification email that layout was removed.
-   *
-   * @param projectId
-   *          identifier of the project
-   * @param layoutName
-   *          name of the layout
-   * @param email
-   *          notification email
-   * @throws MessagingException
-   *           thrown when there is a problem with sending email
-   */
-  protected void sendSuccesfullRemoveEmail(String projectId, String layoutName, String email)
-      throws MessagingException {
-    StringBuilder content = new StringBuilder(
-        "Layout " + layoutName + " in map " + projectId + " was successfully removed.<br/>");
-    emailSender.sendEmail("MapViewer notification", content.toString(), email);
-  }
-
-  /**
-   * Sends notification email that layout was generated.
-   *
-   * @param params
-   *          list of {@link CreateLayoutParams params} used for layout creation
-   * @param schemas
-   *          set of schemas used in coloring
-   * @throws MessagingException
-   *           thrown when there is a problem with sending email
-   */
-  protected void sendSuccessfullGenerationEmail(final CreateLayoutParams params, final Collection<ColorSchema> schemas)
-      throws MessagingException {
-    StringBuilder content = new StringBuilder("Layout " + params.getName() + " generated successfully.\n");
-    content.append("Result of coloring:<br/>");
-
-    String table = prepareTableResult(schemas, new ColorSchemaReader());
-    content.append(table);
-    String email = params.getModel().getProject().getNotifyEmail();
-    if (params.getUser() != null) { // send email to a user who owns the layout
-      emailSender.sendEmail("MapViewer notification", content.toString(), params.getUser());
-
-      // send email to the model owner
-      if (email != null && !email.equals(params.getUser().getEmail())) {
-        content = new StringBuilder("");
-        String username = "UNKNOWN";
-        if (params.getUser() != null) {
-          username = params.getUser().getLogin();
-        }
-        content.append(
-            "User " + username + " created layout in " + params.getModel().getProject().getProjectId() + " map.");
-
-        emailSender.sendEmail("MapViewer notification", content.toString(), email);
-      }
-    } else if (email != null) {
-      // if nobody owns the layout then send it to the model owner
-      emailSender.sendEmail("MapViewer notification", content.toString(), email);
-    }
-  }
-
-  /**
-   * Prepares table with statistics about coloring.
-   *
-   * @param schemas
-   *          schemas that were used for coloring
-   * @param scr
-   *          interface that returns list of columns that should be printed
-   * @return table with statistics about coloring
-   */
-  protected String prepareTableResult(Collection<ColorSchema> schemas, ColorSchemaReader scr) {
-    StringBuilder sb = new StringBuilder("");
-
-    Collection<ColorSchemaColumn> columns = scr.getSetColorSchemaColumns(schemas);
-
-    for (ColorSchemaColumn column : ColorSchemaColumn.values()) {
-      if (columns.contains(column)) {
-        sb.append(column.getTitle() + "\t");
-      }
-    }
-    sb.append("matches<br/>\n");
-
-    for (ColorSchema originalSchema : schemas) {
-      for (ColorSchema schema : splitColorSchema(originalSchema)) {
-        sb.append(prepareTableRow(columns, schema));
-      }
-    }
-
-    return sb.toString();
-  }
-
-  /**
-   * {@link ColorSchema} sometimes contains merged value from few rows. This
-   * method split single {@link ColorSchema} object to simple flat objects that
-   * can be serialiazed in a simple tab separated file.
-   *
-   * @param originalSchema
-   *          original {@link ColorSchema} objcet that we want to spli into flat
-   *          objects
-   * @return {@link List} of flat schema objects obtained from input
-   */
-  private List<ColorSchema> splitColorSchema(ColorSchema originalSchema) {
-    List<ColorSchema> result = new ArrayList<>();
-    if (originalSchema instanceof GenericColorSchema) {
-      result.add(originalSchema);
-    } else if (originalSchema instanceof GeneVariationColorSchema) {
-      for (GeneVariation gv : ((GeneVariationColorSchema) originalSchema).getGeneVariations()) {
-        GeneVariationColorSchema copy = (GeneVariationColorSchema) originalSchema.copy();
-        copy.getGeneVariations().clear();
-        copy.addGeneVariation(gv.copy());
-        result.add(copy);
-      }
-    } else {
-      throw new InvalidArgumentException("Unknown class type: " + originalSchema.getClass());
-    }
-    return result;
-  }
-
-  /**
-   * Prepares tab separated {@link String} represenation of {@link ColorSchema}.
-   *
-   * @param columns
-   *          columns that should be outputed in the result String
-   * @param schema
-   *          input ColorSchema that is going to be transformed into String
-   *          representation
-   * @return tab separated {@link String} represenation of {@link ColorSchema}
-   */
-  protected String prepareTableRow(Collection<ColorSchemaColumn> columns, ColorSchema schema) {
-    StringBuilder sb = new StringBuilder();
-    for (ColorSchemaColumn column : ColorSchemaColumn.values()) {
-      if (columns.contains(column)) {
-        if (schema instanceof GenericColorSchema) {
-          sb.append(prepareTableCellForGenericSchema((GenericColorSchema) schema, column));
-        } else if (schema instanceof GeneVariationColorSchema) {
-          sb.append(prepareTableCellForGeneVariationSchema((GeneVariationColorSchema) schema, column));
-        } else {
-          throw new InvalidArgumentException("Unknown schema type: " + schema.getClass());
-        }
-      }
-    }
-    sb.append(schema.getMatches() + "<br/>\n");
-    return sb.toString();
-  }
-
-  /**
-   * Returns String representing data of {@link GenericColorSchema} that should
-   * appear in a given {@link ColorSchemaColumn}.
-   *
-   * @param schema
-   *          object for which data will be returned
-   * @param column
-   *          column for which data should be returned
-   * @return {@link String} representing data of {@link GenericColorSchema} that
-   *         should appear in a given {@link ColorSchemaColumn}
-   */
-  protected String prepareTableCellForGenericSchema(GenericColorSchema schema, ColorSchemaColumn column) {
-    StringBuilder sb = new StringBuilder();
-    if (column.equals(ColorSchemaColumn.COLOR)) {
-      if (schema.getColor() != null) {
-        sb.append("#" + Integer.toHexString(schema.getColor().getRGB()).substring(2).toUpperCase());
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.NAME)) {
-      sb.append(schema.getName() + "\t");
-    } else if (column.equals(ColorSchemaColumn.MODEL_NAME)) {
-      sb.append(schema.getModelName() + "\t");
-    } else if (column.equals(ColorSchemaColumn.VALUE)) {
-      sb.append(schema.getValue() + "\t");
-    } else if (column.equals(ColorSchemaColumn.COMPARTMENT)) {
-      for (String str : schema.getCompartments()) {
-        sb.append(str + ", ");
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.TYPE)) {
-      for (Class<? extends Element> str : schema.getTypes()) {
-        sb.append(str.getSimpleName() + ", ");
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.IDENTIFIER)) {
-      for (MiriamData md : schema.getMiriamData()) {
-        sb.append(md.getDataType().getCommonName() + ": " + md.getResource() + ", ");
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.ELEMENT_IDENTIFIER)) {
-      sb.append(schema.getElementId() + "\t");
-    } else if (column.equals(ColorSchemaColumn.LINE_WIDTH)) {
-      sb.append(schema.getLineWidth() + "\t");
-    } else if (column.equals(ColorSchemaColumn.REVERSE_REACTION)) {
-      sb.append(schema.getReverseReaction() + "\t");
-    } else if (column.equals(ColorSchemaColumn.POSITION)) {
-      sb.append(schema.getReverseReaction() + "\t");
-    } else if (column.equals(ColorSchemaColumn.DESCRIPTION)) {
-      sb.append(schema.getDescription() + "\t");
-    } else {
-      throw new InvalidArgumentException("Unknown column type: " + column + " for schema type: " + schema.getClass());
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Returns String representing data of {@link GeneVariationColorSchema} that
-   * should appear in a given {@link ColorSchemaColumn}.
-   *
-   * @param schema
-   *          object for which data will be returned
-   * @param column
-   *          column for which data should be returned
-   * @return {@link String} representing data of {@link GeneVariationColorSchema}
-   *         that should appear in a given {@link ColorSchemaColumn}
-   */
-  protected String prepareTableCellForGeneVariationSchema(GeneVariationColorSchema schema, ColorSchemaColumn column) {
-    StringBuilder sb = new StringBuilder();
-    if (column.equals(ColorSchemaColumn.COLOR)) {
-      if (schema.getColor() != null) {
-        sb.append("#" + Integer.toHexString(schema.getColor().getRGB()).substring(2).toUpperCase());
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.NAME)) {
-      sb.append(schema.getName() + "\t");
-    } else if (column.equals(ColorSchemaColumn.MODEL_NAME)) {
-      sb.append(schema.getModelName() + "\t");
-    } else if (column.equals(ColorSchemaColumn.VALUE)) {
-      sb.append(schema.getValue() + "\t");
-    } else if (column.equals(ColorSchemaColumn.COMPARTMENT)) {
-      for (String str : schema.getCompartments()) {
-        sb.append(str + ", ");
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.TYPE)) {
-      for (Class<? extends Element> str : schema.getTypes()) {
-        sb.append(str.getSimpleName() + ", ");
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.IDENTIFIER)) {
-      for (MiriamData md : schema.getMiriamData()) {
-        sb.append(md.getDataType().getCommonName() + ": " + md.getResource() + ", ");
-      }
-      sb.append("\t");
-    } else if (column.equals(ColorSchemaColumn.ELEMENT_IDENTIFIER)) {
-      sb.append(schema.getElementId() + "\t");
-    } else if (column.equals(ColorSchemaColumn.LINE_WIDTH)) {
-      sb.append(schema.getLineWidth() + "\t");
-    } else if (column.equals(ColorSchemaColumn.REVERSE_REACTION)) {
-      sb.append(schema.getReverseReaction() + "\t");
-    } else if (column.equals(ColorSchemaColumn.POSITION)) {
-      sb.append(schema.getGeneVariations().get(0).getPosition() + "\t");
-    } else if (column.equals(ColorSchemaColumn.DESCRIPTION)) {
-      sb.append(schema.getDescription() + "\t");
-    } else if (column.equals(ColorSchemaColumn.ORIGINAL_DNA)) {
-      sb.append(schema.getGeneVariations().get(0).getOriginalDna() + "\t");
-    } else if (column.equals(ColorSchemaColumn.ALTERNATIVE_DNA)) {
-      sb.append(schema.getGeneVariations().get(0).getModifiedDna() + "\t");
-    } else if (column.equals(ColorSchemaColumn.REFERENCE_GENOME_TYPE)) {
-      sb.append(schema.getGeneVariations().get(0).getReferenceGenomeType() + "\t");
-    } else if (column.equals(ColorSchemaColumn.REFERENCE_GENOME_VERSION)) {
-      sb.append(schema.getGeneVariations().get(0).getReferenceGenomeVersion() + "\t");
-    } else if (column.equals(ColorSchemaColumn.CONTIG)) {
-      sb.append(schema.getGeneVariations().get(0).getContig() + "\t");
-    } else if (column.equals(ColorSchemaColumn.REFERENCES)) {
-      MiriamConnector mc = new MiriamConnector();
-      for (MiriamData md : schema.getGeneVariations().get(0).getReferences()) {
-        sb.append(mc.miriamDataToUri(md) + "\t");
-      }
-    } else {
-      throw new InvalidArgumentException("Unknown column type: " + column + " for schema type: " + schema.getClass());
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Returns byte array containing data from original input file that was used to
-   * generate the layout.
-   *
-   * @param layoutId
-   *          identifier of layout for which we want to retrieve original file
-   *          data
-   * @return original data file for given layout, if such file is not stored in
-   *         database (compatibility reasons) then null is returned
-   * @throws SecurityException
-   */
-  private byte[] getInputDataForLayout(int layoutId, String token) throws SecurityException {
-    Layout layout = getLayoutById(layoutId, token);
-    if (layout == null) {
-      return null;
-    } else {
-      if (layout.getInputData() != null) {
-        return layout.getInputData().getFileContent();
-      } else {
-        return null;
-      }
-    }
-  }
-
-  @Override
-  public List<LightLayoutAliasView> getAliasesForLayout(Model model, int layoutId, String token)
-      throws SecurityException {
-    try {
-      ColorSchemaReader reader = new ColorSchemaReader();
-      Collection<ColorSchema> schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-      // colors here are not important
-      ColorModelCommand command = new ColorModelCommand(model, schemas,
-          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-      LightLayoutAliasViewFactory factory = new LightLayoutAliasViewFactory();
-      List<LightLayoutAliasView> result = new ArrayList<>();
-      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
-        if (entry.getKey() instanceof Element) {
-          result.add(factory.create(new Pair<Element, ColorSchema>((Element) entry.getKey(), entry.getValue())));
-        }
-      }
-      return result;
-    } catch (InvalidColorSchemaException e) {
-      throw new InvalidStateException(e);
-    } catch (IOException e) {
-      throw new InvalidStateException(e);
-    }
-  }
-
-  @Override
-  public List<LightLayoutReactionView> getReactionsForLayout(Model model, int layoutId, String token)
-      throws SecurityException {
-    try {
-      ColorSchemaReader reader = new ColorSchemaReader();
-      Collection<ColorSchema> schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-      // colors here are not important
-      ColorModelCommand command = new ColorModelCommand(model, schemas,
-          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-      LightLayoutReactionViewFactory factory = new LightLayoutReactionViewFactory();
-      List<LightLayoutReactionView> result = new ArrayList<>();
-      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
-        if (entry.getKey() instanceof Reaction) {
-          result.add(factory.create(new Pair<Reaction, ColorSchema>((Reaction) entry.getKey(), entry.getValue())));
-        }
-      }
-      return result;
-    } catch (InvalidColorSchemaException e) {
-      throw new InvalidStateException(e);
-    } catch (IOException e) {
-      throw new InvalidStateException(e);
-    }
-  }
-
-  @Override
-  public Map<Object, ColorSchema> getElementsForLayout(Model model, Integer layoutId, String token)
-      throws SecurityException {
-    try {
-      ColorSchemaReader reader = new ColorSchemaReader();
-      Collection<ColorSchema> schemas;
-      schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-      // colors here are not important
-      ColorModelCommand command = new ColorModelCommand(model, schemas,
-          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-      return command.getModifiedElements();
-    } catch (InvalidColorSchemaException e) {
-      throw new InvalidStateException(e);
-    } catch (IOException e) {
-      throw new InvalidStateException(e);
-    }
-  }
-
-  @Override
-  public EmailSender getEmailSender() {
-    return emailSender;
-  }
-
-  @Override
-  public void setEmailSender(EmailSender emailSender) {
-    this.emailSender = emailSender;
-  }
-
-  @Override
-  public List<Layout> getCustomLayouts(Model model, String token, Boolean publicOverlay, User creator)
-      throws SecurityException {
-    User user = userService.getUserByToken(token);
-    List<Layout> result = new ArrayList<>();
-    if (model == null || user == null) {
-      return result;
-    }
-    List<Layout> overlays = layoutDao.getLayoutsByModel(model, creator, publicOverlay);
-    for (Layout overlay : overlays) {
-      if (userCanViewOverlay(overlay, user)) {
-        result.add(overlay);
-      }
-    }
-    Collections.sort(result, Layout.ID_COMPARATOR);
-    return result;
-  }
-
-  @Override
-  public Layout getLayoutById(int overlayId, String token) throws SecurityException {
-    Layout layout = layoutDao.getById(overlayId);
-    if (layout == null) {
-      return null;
-    }
-    User user = userService.getUserByToken(token);
-    if (!userCanViewOverlay(layout, user)) {
-      throw new SecurityException("User doesn't have access to overlay");
-    }
-    return layout;
-  }
-
-  @Override
-  public FullLayoutAliasView getFullAliasForLayout(Model model, Integer id, int layoutId, String token)
-      throws SecurityException {
-    try {
-      ColorSchemaReader reader = new ColorSchemaReader();
-      Collection<ColorSchema> schemas;
-      schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-      // colors here are not important
-      ColorModelCommand command = new ColorModelCommand(model, schemas,
-          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-      FullLayoutAliasViewFactory factory = new FullLayoutAliasViewFactory();
-
-      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
-        if (entry.getKey() instanceof Element) {
-          Element alias = (Element) entry.getKey();
-          if (id.equals(alias.getId())) {
-            return factory.create(new Pair<Element, ColorSchema>(alias, entry.getValue()));
-          }
-        }
-      }
-      return null;
-    } catch (InvalidColorSchemaException e) {
-      throw new InvalidStateException(e);
-    } catch (IOException e) {
-      throw new InvalidStateException(e);
-    }
-  }
-
-  @Override
-  public FullLayoutReactionView getFullReactionForLayout(Model model, Integer id, int layoutId, String token)
-      throws SecurityException {
-    try {
-      ColorSchemaReader reader = new ColorSchemaReader();
-      Collection<ColorSchema> schemas;
-      schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-      // colors here are not important
-      ColorModelCommand command = new ColorModelCommand(model, schemas,
-          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-      FullLayoutReactionViewFactory factory = new FullLayoutReactionViewFactory();
-
-      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
-        if (entry.getKey() instanceof Reaction) {
-          Reaction alias = (Reaction) entry.getKey();
-          if (id.equals(alias.getId())) {
-            return factory.create(new Pair<Reaction, ColorSchema>(alias, entry.getValue()));
-          }
-        }
-      }
-      return null;
-    } catch (InvalidColorSchemaException e) {
-      throw new InvalidStateException(e);
-    } catch (IOException e) {
-      throw new InvalidStateException(e);
-    }
-  }
-
-  @Override
-  public boolean userCanRemoveLayout(Layout layout, String authenticationToken) throws SecurityException {
-    User user = userService.getUserByToken(authenticationToken);
-    return userCanRemoveLayout(layout, user);
-  }
-}
+package lcsb.mapviewer.services.impl;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+import javax.mail.MessagingException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import lcsb.mapviewer.annotation.services.MiriamConnector;
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.commands.ColorModelCommand;
+import lcsb.mapviewer.commands.CommandExecutionException;
+import lcsb.mapviewer.commands.CopyCommand;
+import lcsb.mapviewer.common.IProgressUpdater;
+import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.TextFileUtils;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.converter.graphics.MapGenerator;
+import lcsb.mapviewer.converter.graphics.MapGenerator.MapGeneratorParams;
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.cache.UploadedFileEntry;
+import lcsb.mapviewer.model.log.LogType;
+import lcsb.mapviewer.model.map.MiriamData;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.GeneVariation;
+import lcsb.mapviewer.model.map.layout.GeneVariationColorSchema;
+import lcsb.mapviewer.model.map.layout.GenericColorSchema;
+import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
+import lcsb.mapviewer.model.map.layout.Layout;
+import lcsb.mapviewer.model.map.layout.LayoutStatus;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
+import lcsb.mapviewer.model.map.reaction.Reaction;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.user.ObjectPrivilege;
+import lcsb.mapviewer.model.user.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.persist.DbUtils;
+import lcsb.mapviewer.persist.dao.map.LayoutDao;
+import lcsb.mapviewer.services.SecurityException;
+import lcsb.mapviewer.services.interfaces.IConfigurationService;
+import lcsb.mapviewer.services.interfaces.ILayoutService;
+import lcsb.mapviewer.services.interfaces.ILogService;
+import lcsb.mapviewer.services.interfaces.ILogService.LogParams;
+import lcsb.mapviewer.services.interfaces.IUserService;
+import lcsb.mapviewer.services.search.layout.FullLayoutAliasView;
+import lcsb.mapviewer.services.search.layout.FullLayoutAliasViewFactory;
+import lcsb.mapviewer.services.search.layout.FullLayoutReactionView;
+import lcsb.mapviewer.services.search.layout.FullLayoutReactionViewFactory;
+import lcsb.mapviewer.services.search.layout.LightLayoutAliasView;
+import lcsb.mapviewer.services.search.layout.LightLayoutAliasViewFactory;
+import lcsb.mapviewer.services.search.layout.LightLayoutReactionView;
+import lcsb.mapviewer.services.search.layout.LightLayoutReactionViewFactory;
+import lcsb.mapviewer.services.utils.ColorSchemaReader;
+import lcsb.mapviewer.services.utils.EmailSender;
+import lcsb.mapviewer.services.utils.data.ColorSchemaColumn;
+
+/**
+ * Implementation of the layout service.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Transactional(value = "txManager")
+public class LayoutService implements ILayoutService {
+
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(LayoutService.class);
+
+  /**
+   * Layout data access object.
+   */
+  @Autowired
+  private LayoutDao layoutDao;
+
+  /**
+   * Service that manages and gives access to user information.
+   */
+  @Autowired
+  private IUserService userService;
+
+  /**
+   * Service used to access logs.
+   *
+   * @see ILogService
+   */
+  @Autowired
+  private ILogService logService;
+
+  /**
+   * Service that manages and gives access to configuration parameters.
+   */
+  @Autowired
+  private IConfigurationService configurationService;
+
+  /**
+   * Utility class that helps to manage the sessions in custom multi-threaded
+   * implementation.
+   */
+  @Autowired
+  private DbUtils dbUtils;
+
+  /**
+   * Object that sends emails.
+   */
+  private EmailSender emailSender;
+
+  /**
+   * Method called after spring initialized all interfaces.
+   */
+  @PostConstruct
+  public void springInit() {
+    emailSender = new EmailSender(configurationService);
+  }
+
+  @Override
+  public boolean userCanAddLayout(Model model, User user) {
+    // if we don't have privileges to view the object then we cannot add layouts
+    if (!userService.userHasPrivilege(user, PrivilegeType.VIEW_PROJECT, model.getProject())) {
+      return false;
+    }
+    long count = getAvailableCustomLayoutsNumber(user);
+    return count > 0;
+  }
+
+  @Override
+  public long getAvailableCustomLayoutsNumber(User user) {
+    long level = userService.getUserPrivilegeLevel(user, PrivilegeType.CUSTOM_LAYOUTS);
+    long layouts = layoutDao.getCountByUser(user);
+    return level - layouts;
+
+  }
+
+  @Override
+  public boolean userCanRemoveLayout(Layout layout, User user) {
+    User creator = layout.getCreator();
+    Project project = layout.getModel().getProject();
+    if (creator == null) {
+      return userService.userHasPrivilege(user, PrivilegeType.LAYOUT_MANAGEMENT, project);
+    } else {
+      return creator.getId().equals(user.getId())
+          || userService.userHasPrivilege(user, PrivilegeType.LAYOUT_MANAGEMENT, project);
+    }
+  }
+
+  private boolean userCanViewOverlay(Layout overlay, User user) {
+    if (overlay.isPublicLayout()) {
+      return true;
+    }
+    if (overlay.getCreator() == null) {
+      return true;
+    }
+    if (overlay.getCreator().getLogin().equals(user.getLogin())) {
+      return true;
+    }
+
+    if (userService.userHasPrivilege(user, PrivilegeType.LAYOUT_VIEW, overlay)) {
+      return true;
+    }
+    if (userService.userHasPrivilege(user, PrivilegeType.LAYOUT_MANAGEMENT, overlay.getModel().getProject())) {
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public void removeLayout(Layout layout, final String homeDir) throws IOException {
+    final String dir;
+    if (homeDir != null) {
+      if (layout.getModel().getProject().getDirectory() != null) {
+        dir = homeDir + "/../map_images/" + layout.getModel().getProject().getDirectory() + "/";
+      } else {
+        dir = homeDir + "/../map_images/";
+      }
+    } else {
+      dir = null;
+    }
+
+    String projectId = layout.getModel().getProject().getProjectId();
+    final String email;
+    User user = layout.getCreator();
+    if (user != null) {
+      email = user.getEmail();
+    } else {
+      email = null;
+    }
+
+    layout.getModel().removeLayout(layout);
+    layoutDao.delete(layout);
+
+    LogParams params = new LogParams().object(layout).type(LogType.LAYOUT_REMOVED);
+    logService.log(params);
+
+    if (email != null) {
+      Thread sendEmailThread = new Thread(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            sendSuccesfullRemoveEmail(projectId, layout.getTitle(), email);
+          } catch (MessagingException e) {
+            logger.error(e);
+          }
+        }
+      });
+      sendEmailThread.start();
+    }
+    Thread removeFilesThread = new Thread(new Runnable() {
+      @Override
+      public void run() {
+        MapGenerator generator = new MapGenerator();
+        try {
+          generator.removeLayout(layout, dir);
+        } catch (IOException e) {
+          logger.error(e);
+        }
+
+      }
+    });
+    removeFilesThread.start();
+  }
+
+  @Override
+  public void updateLayout(Layout layout) {
+    layoutDao.update(layout);
+  }
+
+  @Override
+  public void addViewPrivilegeToLayout(Layout layout, User user) {
+    ObjectPrivilege privilege = new ObjectPrivilege();
+    privilege.setIdObject(layout.getId());
+    privilege.setLevel(1);
+    privilege.setType(PrivilegeType.LAYOUT_VIEW);
+    privilege.setUser(user);
+    userService.setUserPrivilege(user, privilege);
+  }
+
+  @Override
+  public void dropViewPrivilegeFromLayout(Layout layout, User user) {
+    ObjectPrivilege privilege = new ObjectPrivilege();
+    privilege.setIdObject(layout.getId());
+    privilege.setLevel(0);
+    privilege.setType(PrivilegeType.LAYOUT_VIEW);
+    privilege.setUser(user);
+    userService.setUserPrivilege(user, privilege);
+  }
+
+  @Override
+  public Layout createLayoutWithImages(final CreateLayoutParams params)
+      throws IOException, InvalidColorSchemaException, CommandExecutionException {
+    ColorSchemaReader reader = new ColorSchemaReader();
+    final Collection<ColorSchema> schemas = reader.readColorSchema(params.getColorInputStream(),
+        TextFileUtils.getHeaderParametersFromFile(params.getColorInputStream()));
+    final Model colorModel = new CopyCommand(params.getModel()).execute();
+    new ColorModelCommand(params.getModel(), schemas, userService.getColorExtractorForUser(params.getUser())).execute();
+    String[] tmp = params.getDirectory().split("[\\\\/]");
+    String simpleDir = tmp[tmp.length - 1];
+
+    layoutDao.flush();
+
+    boolean customSession = false;
+    if (params.isAsync()) {
+      customSession = !dbUtils.isCustomSessionForCurrentThread();
+      if (customSession) {
+        dbUtils.createSessionForCurrentThread();
+      }
+    }
+    final Map<Model, Integer> layoutIdByModel = new HashMap<>();
+
+    Layout topLayout = new Layout(params.getName(), simpleDir, false);
+    if (params.getUser() == null) {
+      topLayout.setPublicLayout(true);
+    } else {
+      topLayout.setPublicLayout(false);
+    }
+    topLayout.setStatus(LayoutStatus.NA);
+    topLayout.setProgress(0.0);
+    UploadedFileEntry fileEntry = new UploadedFileEntry();
+    fileEntry.setFileContent(IOUtils.toByteArray(params.getColorInputStream()));
+    fileEntry.setOriginalFileName(params.getLayoutFileName());
+    fileEntry.setLength(fileEntry.getFileContent().length);
+    fileEntry.setOwner(params.getUser());
+    topLayout.setInputData(fileEntry);
+    topLayout.setDescription(params.getDescription());
+    params.getModel().addLayout(topLayout);
+    topLayout.setCreator(params.getUser());
+    layoutDao.add(topLayout);
+    topLayout.setDirectory(simpleDir + topLayout.getId());
+
+    layoutDao.update(topLayout);
+
+    layoutIdByModel.put(colorModel, topLayout.getId());
+
+    for (ModelSubmodelConnection connection : params.getModel().getSubmodelConnections()) {
+      Layout layout = new Layout(params.getName(), simpleDir, false);
+      layout.setStatus(LayoutStatus.NA);
+      layout.setProgress(0.0);
+      connection.getSubmodel().getModel().addLayout(layout);
+      layout.setCreator(params.getUser());
+      layout.setPublicLayout(false);
+      topLayout.addLayout(layout);
+      layoutDao.add(layout);
+      layout.setDirectory(simpleDir + layout.getId());
+
+      layoutDao.update(layout);
+
+      layoutIdByModel.put(colorModel.getSubmodelByConnectionName(connection.getName()), layout.getId());
+    }
+
+    if (params.isAsync()) {
+      if (customSession) {
+        dbUtils.closeSessionForCurrentThread();
+      } else {
+        layoutDao.commit();
+      }
+    }
+    final int layoutId = layoutIdByModel.get(colorModel);
+
+    Thread computations = new Thread(new Runnable() {
+      @Override
+      public void run() {
+        if (params.isAsync()) {
+          // open transaction for this thread
+          dbUtils.createSessionForCurrentThread();
+        }
+
+        try {
+          MapGenerator generator = new MapGenerator();
+          final int models = layoutIdByModel.entrySet().size();
+
+          int count = 0;
+          for (Model m : layoutIdByModel.keySet()) {
+            final int counted = count;
+            int id = layoutIdByModel.get(m);
+            MapGeneratorParams imgParams = generator.new MapGeneratorParams().model(m)
+                .directory(params.getDirectory() + id).updater(new IProgressUpdater() {
+                  private int lastProgress = -1;
+
+                  @Override
+                  public void setProgress(double progress) {
+                    progress = progress / ((double) models) + ((double) counted * MAX_PROGRESS) / ((double) models);
+                    if (((int) progress) != lastProgress) {
+                      Layout layout = layoutDao.getById(layoutId);
+                      lastProgress = (int) progress;
+                      layout.setProgress(progress);
+                      layout.setStatus(LayoutStatus.GENERATING);
+                      layoutDao.update(layout);
+                      if (params.isAsync()) {
+                        layoutDao.commit();
+                      }
+                    }
+                  }
+                });
+            imgParams.sbgn(params.getModel().getProject().isSbgnFormat());
+            generator.generateMapImages(imgParams);
+            count++;
+          }
+          Layout layout = layoutDao.getById(layoutId);
+          layout.setProgress(IProgressUpdater.MAX_PROGRESS);
+          layout.setStatus(LayoutStatus.OK);
+          layoutDao.update(layout);
+          if (params.isAsync()) {
+            layoutDao.commit();
+          }
+
+          try {
+            sendSuccessfullGenerationEmail(params, schemas);
+          } catch (MessagingException e) {
+            logger.error("Problem with sending email", e);
+          }
+          logService
+              .log(new LogParams().object(layout).description("Created successfully.").type(LogType.LAYOUT_CREATED));
+        } catch (Exception e) {
+          logger.error("Problem with creating layout", e);
+
+          Layout layout = layoutDao.getById(layoutId);
+          layout.setProgress(IProgressUpdater.MAX_PROGRESS);
+          layout.setStatus(LayoutStatus.FAILURE);
+          layoutDao.update(layout);
+
+          try {
+            emailSender.sendEmail("MapViewer status", "There was a problem with generating layout " + params.getName()
+                + ". Contact administrator to solve this issue.", params.getUser());
+          } catch (MessagingException e1) {
+            logger.error("Problem with sending email", e1);
+          }
+          logService
+              .log(new LogParams().object(layout).description("Problem during creation.").type(LogType.LAYOUT_CREATED));
+        }
+        if (params.isAsync()) {
+          // close the transaction for this thread
+          dbUtils.closeSessionForCurrentThread();
+        }
+      }
+    });
+
+    if (params.isAsync()) {
+      computations.start();
+    } else {
+      computations.run();
+    }
+    return topLayout;
+  }
+
+  @Override
+  public Layout createLayout(final CreateLayoutParams params) throws IOException, InvalidColorSchemaException {
+    ColorSchemaReader reader = new ColorSchemaReader();
+    final Collection<ColorSchema> schemas = reader.readColorSchema(params.getColorInputStream(),
+        TextFileUtils.getHeaderParametersFromFile(params.getColorInputStream()));
+
+    // check if we can color our model using this schema,
+    // if not then exception will be thrown and passed up
+    try {
+      Model copy = new CopyCommand(params.getModel()).execute();
+      new ColorModelCommand(copy, schemas, userService.getColorExtractorForUser(params.getUser())).execute();
+    } catch (CommandExecutionException e) {
+      throw new InvalidColorSchemaException(e);
+    }
+
+    String[] tmp = params.getDirectory().split("[\\\\/]");
+    String simpleDir = tmp[tmp.length - 1];
+
+    layoutDao.flush();
+
+    Layout topLayout = new Layout(params.getName(), simpleDir, false);
+    if (params.getUser() == null) {
+      topLayout.setPublicLayout(true);
+    } else {
+      topLayout.setPublicLayout(false);
+    }
+    topLayout.setGoogleLicenseConsent(params.isGoogleLicenseConsent());
+    topLayout.setStatus(LayoutStatus.OK);
+    topLayout.setProgress(0.0);
+    UploadedFileEntry fileEntry = new UploadedFileEntry();
+    fileEntry.setFileContent(IOUtils.toByteArray(params.getColorInputStream()));
+    fileEntry.setOriginalFileName(params.getLayoutFileName());
+    fileEntry.setLength(fileEntry.getFileContent().length);
+    fileEntry.setOwner(params.getUser());
+    topLayout.setInputData(fileEntry);
+    topLayout.setDescription(params.getDescription());
+    params.getModel().addLayout(topLayout);
+    topLayout.setCreator(params.getUser());
+    layoutDao.add(topLayout);
+    topLayout.setDirectory(simpleDir + topLayout.getId());
+
+    layoutDao.update(topLayout);
+
+    for (ModelSubmodelConnection connection : params.getModel().getSubmodelConnections()) {
+      Layout layout = new Layout(params.getName(), simpleDir, false);
+      layout.setStatus(LayoutStatus.OK);
+      layout.setProgress(0.0);
+      connection.getSubmodel().getModel().addLayout(layout);
+      layout.setCreator(params.getUser());
+      layout.setPublicLayout(false);
+      topLayout.addLayout(layout);
+      layoutDao.add(layout);
+      layout.setDirectory(simpleDir + layout.getId());
+
+      layoutDao.update(layout);
+    }
+
+    Thread computations = new Thread(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          // open transaction for this thread
+          dbUtils.createSessionForCurrentThread();
+          sendSuccessfullGenerationEmail(params, schemas);
+        } catch (MessagingException e) {
+          logger.error("Problem with sending email", e);
+        } finally {
+          dbUtils.closeSessionForCurrentThread();
+        }
+      }
+    });
+
+    LogParams logParams = new LogParams().object(topLayout).description("Created successfully.")
+        .type(LogType.LAYOUT_CREATED);
+    logService.log(logParams);
+
+    computations.start();
+    return topLayout;
+  }
+
+  /**
+   * @return the configurationService
+   * @see #configurationService
+   */
+  public IConfigurationService getConfigurationService() {
+    return configurationService;
+  }
+
+  /**
+   * @param configurationService
+   *          the configurationService to set
+   * @see #configurationService
+   */
+  public void setConfigurationService(IConfigurationService configurationService) {
+    this.configurationService = configurationService;
+  }
+
+  /**
+   * @return the dbUtils
+   * @see #dbUtils
+   */
+  public DbUtils getDbUtils() {
+    return dbUtils;
+  }
+
+  /**
+   * @param dbUtils
+   *          the dbUtils to set
+   * @see #dbUtils
+   */
+  public void setDbUtils(DbUtils dbUtils) {
+    this.dbUtils = dbUtils;
+  }
+
+  /**
+   * @return the userService
+   * @see #userService
+   */
+  public IUserService getUserService() {
+    return userService;
+  }
+
+  /**
+   * @param userService
+   *          the userService to set
+   * @see #userService
+   */
+  public void setUserService(IUserService userService) {
+    this.userService = userService;
+  }
+
+  /**
+   * Sends notification email that layout was removed.
+   *
+   * @param projectId
+   *          identifier of the project
+   * @param layoutName
+   *          name of the layout
+   * @param email
+   *          notification email
+   * @throws MessagingException
+   *           thrown when there is a problem with sending email
+   */
+  protected void sendSuccesfullRemoveEmail(String projectId, String layoutName, String email)
+      throws MessagingException {
+    StringBuilder content = new StringBuilder(
+        "Layout " + layoutName + " in map " + projectId + " was successfully removed.<br/>");
+    emailSender.sendEmail("MapViewer notification", content.toString(), email);
+  }
+
+  /**
+   * Sends notification email that layout was generated.
+   *
+   * @param params
+   *          list of {@link CreateLayoutParams params} used for layout creation
+   * @param schemas
+   *          set of schemas used in coloring
+   * @throws MessagingException
+   *           thrown when there is a problem with sending email
+   */
+  protected void sendSuccessfullGenerationEmail(final CreateLayoutParams params, final Collection<ColorSchema> schemas)
+      throws MessagingException {
+    StringBuilder content = new StringBuilder("Layout " + params.getName() + " generated successfully.\n");
+    content.append("Result of coloring:<br/>");
+
+    String table = prepareTableResult(schemas, new ColorSchemaReader());
+    content.append(table);
+    String email = params.getModel().getProject().getNotifyEmail();
+    if (params.getUser() != null) { // send email to a user who owns the layout
+      emailSender.sendEmail("MapViewer notification", content.toString(), params.getUser());
+
+      // send email to the model owner
+      if (email != null && !email.equals(params.getUser().getEmail())) {
+        content = new StringBuilder("");
+        String username = "UNKNOWN";
+        if (params.getUser() != null) {
+          username = params.getUser().getLogin();
+        }
+        content.append(
+            "User " + username + " created layout in " + params.getModel().getProject().getProjectId() + " map.");
+
+        emailSender.sendEmail("MapViewer notification", content.toString(), email);
+      }
+    } else if (email != null) {
+      // if nobody owns the layout then send it to the model owner
+      emailSender.sendEmail("MapViewer notification", content.toString(), email);
+    }
+  }
+
+  /**
+   * Prepares table with statistics about coloring.
+   *
+   * @param schemas
+   *          schemas that were used for coloring
+   * @param scr
+   *          interface that returns list of columns that should be printed
+   * @return table with statistics about coloring
+   */
+  protected String prepareTableResult(Collection<ColorSchema> schemas, ColorSchemaReader scr) {
+    StringBuilder sb = new StringBuilder("");
+
+    Collection<ColorSchemaColumn> columns = scr.getSetColorSchemaColumns(schemas);
+
+    for (ColorSchemaColumn column : ColorSchemaColumn.values()) {
+      if (columns.contains(column)) {
+        sb.append(column.getTitle() + "\t");
+      }
+    }
+    sb.append("matches<br/>\n");
+
+    for (ColorSchema originalSchema : schemas) {
+      for (ColorSchema schema : splitColorSchema(originalSchema)) {
+        sb.append(prepareTableRow(columns, schema));
+      }
+    }
+
+    return sb.toString();
+  }
+
+  /**
+   * {@link ColorSchema} sometimes contains merged value from few rows. This
+   * method split single {@link ColorSchema} object to simple flat objects that
+   * can be serialiazed in a simple tab separated file.
+   *
+   * @param originalSchema
+   *          original {@link ColorSchema} objcet that we want to spli into flat
+   *          objects
+   * @return {@link List} of flat schema objects obtained from input
+   */
+  private List<ColorSchema> splitColorSchema(ColorSchema originalSchema) {
+    List<ColorSchema> result = new ArrayList<>();
+    if (originalSchema instanceof GenericColorSchema) {
+      result.add(originalSchema);
+    } else if (originalSchema instanceof GeneVariationColorSchema) {
+      for (GeneVariation gv : ((GeneVariationColorSchema) originalSchema).getGeneVariations()) {
+        GeneVariationColorSchema copy = (GeneVariationColorSchema) originalSchema.copy();
+        copy.getGeneVariations().clear();
+        copy.addGeneVariation(gv.copy());
+        result.add(copy);
+      }
+    } else {
+      throw new InvalidArgumentException("Unknown class type: " + originalSchema.getClass());
+    }
+    return result;
+  }
+
+  /**
+   * Prepares tab separated {@link String} represenation of {@link ColorSchema}.
+   *
+   * @param columns
+   *          columns that should be outputed in the result String
+   * @param schema
+   *          input ColorSchema that is going to be transformed into String
+   *          representation
+   * @return tab separated {@link String} represenation of {@link ColorSchema}
+   */
+  protected String prepareTableRow(Collection<ColorSchemaColumn> columns, ColorSchema schema) {
+    StringBuilder sb = new StringBuilder();
+    for (ColorSchemaColumn column : ColorSchemaColumn.values()) {
+      if (columns.contains(column)) {
+        if (schema instanceof GenericColorSchema) {
+          sb.append(prepareTableCellForGenericSchema((GenericColorSchema) schema, column));
+        } else if (schema instanceof GeneVariationColorSchema) {
+          sb.append(prepareTableCellForGeneVariationSchema((GeneVariationColorSchema) schema, column));
+        } else {
+          throw new InvalidArgumentException("Unknown schema type: " + schema.getClass());
+        }
+      }
+    }
+    sb.append(schema.getMatches() + "<br/>\n");
+    return sb.toString();
+  }
+
+  /**
+   * Returns String representing data of {@link GenericColorSchema} that should
+   * appear in a given {@link ColorSchemaColumn}.
+   *
+   * @param schema
+   *          object for which data will be returned
+   * @param column
+   *          column for which data should be returned
+   * @return {@link String} representing data of {@link GenericColorSchema} that
+   *         should appear in a given {@link ColorSchemaColumn}
+   */
+  protected String prepareTableCellForGenericSchema(GenericColorSchema schema, ColorSchemaColumn column) {
+    StringBuilder sb = new StringBuilder();
+    if (column.equals(ColorSchemaColumn.COLOR)) {
+      if (schema.getColor() != null) {
+        sb.append("#" + Integer.toHexString(schema.getColor().getRGB()).substring(2).toUpperCase());
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.NAME)) {
+      sb.append(schema.getName() + "\t");
+    } else if (column.equals(ColorSchemaColumn.MODEL_NAME)) {
+      sb.append(schema.getModelName() + "\t");
+    } else if (column.equals(ColorSchemaColumn.VALUE)) {
+      sb.append(schema.getValue() + "\t");
+    } else if (column.equals(ColorSchemaColumn.COMPARTMENT)) {
+      for (String str : schema.getCompartments()) {
+        sb.append(str + ", ");
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.TYPE)) {
+      for (Class<? extends Element> str : schema.getTypes()) {
+        sb.append(str.getSimpleName() + ", ");
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.IDENTIFIER)) {
+      for (MiriamData md : schema.getMiriamData()) {
+        sb.append(md.getDataType().getCommonName() + ": " + md.getResource() + ", ");
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.ELEMENT_IDENTIFIER)) {
+      sb.append(schema.getElementId() + "\t");
+    } else if (column.equals(ColorSchemaColumn.LINE_WIDTH)) {
+      sb.append(schema.getLineWidth() + "\t");
+    } else if (column.equals(ColorSchemaColumn.REVERSE_REACTION)) {
+      sb.append(schema.getReverseReaction() + "\t");
+    } else if (column.equals(ColorSchemaColumn.POSITION)) {
+      sb.append(schema.getReverseReaction() + "\t");
+    } else if (column.equals(ColorSchemaColumn.DESCRIPTION)) {
+      sb.append(schema.getDescription() + "\t");
+    } else {
+      throw new InvalidArgumentException("Unknown column type: " + column + " for schema type: " + schema.getClass());
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Returns String representing data of {@link GeneVariationColorSchema} that
+   * should appear in a given {@link ColorSchemaColumn}.
+   *
+   * @param schema
+   *          object for which data will be returned
+   * @param column
+   *          column for which data should be returned
+   * @return {@link String} representing data of {@link GeneVariationColorSchema}
+   *         that should appear in a given {@link ColorSchemaColumn}
+   */
+  protected String prepareTableCellForGeneVariationSchema(GeneVariationColorSchema schema, ColorSchemaColumn column) {
+    StringBuilder sb = new StringBuilder();
+    if (column.equals(ColorSchemaColumn.COLOR)) {
+      if (schema.getColor() != null) {
+        sb.append("#" + Integer.toHexString(schema.getColor().getRGB()).substring(2).toUpperCase());
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.NAME)) {
+      sb.append(schema.getName() + "\t");
+    } else if (column.equals(ColorSchemaColumn.MODEL_NAME)) {
+      sb.append(schema.getModelName() + "\t");
+    } else if (column.equals(ColorSchemaColumn.VALUE)) {
+      sb.append(schema.getValue() + "\t");
+    } else if (column.equals(ColorSchemaColumn.COMPARTMENT)) {
+      for (String str : schema.getCompartments()) {
+        sb.append(str + ", ");
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.TYPE)) {
+      for (Class<? extends Element> str : schema.getTypes()) {
+        sb.append(str.getSimpleName() + ", ");
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.IDENTIFIER)) {
+      for (MiriamData md : schema.getMiriamData()) {
+        sb.append(md.getDataType().getCommonName() + ": " + md.getResource() + ", ");
+      }
+      sb.append("\t");
+    } else if (column.equals(ColorSchemaColumn.ELEMENT_IDENTIFIER)) {
+      sb.append(schema.getElementId() + "\t");
+    } else if (column.equals(ColorSchemaColumn.LINE_WIDTH)) {
+      sb.append(schema.getLineWidth() + "\t");
+    } else if (column.equals(ColorSchemaColumn.REVERSE_REACTION)) {
+      sb.append(schema.getReverseReaction() + "\t");
+    } else if (column.equals(ColorSchemaColumn.POSITION)) {
+      sb.append(schema.getGeneVariations().get(0).getPosition() + "\t");
+    } else if (column.equals(ColorSchemaColumn.DESCRIPTION)) {
+      sb.append(schema.getDescription() + "\t");
+    } else if (column.equals(ColorSchemaColumn.ORIGINAL_DNA)) {
+      sb.append(schema.getGeneVariations().get(0).getOriginalDna() + "\t");
+    } else if (column.equals(ColorSchemaColumn.ALTERNATIVE_DNA)) {
+      sb.append(schema.getGeneVariations().get(0).getModifiedDna() + "\t");
+    } else if (column.equals(ColorSchemaColumn.REFERENCE_GENOME_TYPE)) {
+      sb.append(schema.getGeneVariations().get(0).getReferenceGenomeType() + "\t");
+    } else if (column.equals(ColorSchemaColumn.REFERENCE_GENOME_VERSION)) {
+      sb.append(schema.getGeneVariations().get(0).getReferenceGenomeVersion() + "\t");
+    } else if (column.equals(ColorSchemaColumn.CONTIG)) {
+      sb.append(schema.getGeneVariations().get(0).getContig() + "\t");
+    } else if (column.equals(ColorSchemaColumn.REFERENCES)) {
+      MiriamConnector mc = new MiriamConnector();
+      for (MiriamData md : schema.getGeneVariations().get(0).getReferences()) {
+        sb.append(mc.miriamDataToUri(md) + "\t");
+      }
+    } else {
+      throw new InvalidArgumentException("Unknown column type: " + column + " for schema type: " + schema.getClass());
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Returns byte array containing data from original input file that was used to
+   * generate the layout.
+   *
+   * @param layoutId
+   *          identifier of layout for which we want to retrieve original file
+   *          data
+   * @return original data file for given layout, if such file is not stored in
+   *         database (compatibility reasons) then null is returned
+   * @throws SecurityException
+   */
+  private byte[] getInputDataForLayout(int layoutId, String token) throws SecurityException {
+    Layout layout = getLayoutById(layoutId, token);
+    if (layout == null) {
+      return null;
+    } else {
+      if (layout.getInputData() != null) {
+        return layout.getInputData().getFileContent();
+      } else {
+        return null;
+      }
+    }
+  }
+
+  @Override
+  public List<LightLayoutAliasView> getAliasesForLayout(Model model, int layoutId, String token)
+      throws SecurityException {
+    try {
+      ColorSchemaReader reader = new ColorSchemaReader();
+      Collection<ColorSchema> schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      LightLayoutAliasViewFactory factory = new LightLayoutAliasViewFactory();
+      List<LightLayoutAliasView> result = new ArrayList<>();
+      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
+        if (entry.getKey() instanceof Element) {
+          result.add(factory.create(new Pair<Element, ColorSchema>((Element) entry.getKey(), entry.getValue())));
+        }
+      }
+      return result;
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  @Override
+  public List<LightLayoutReactionView> getReactionsForLayout(Model model, int layoutId, String token)
+      throws SecurityException {
+    try {
+      ColorSchemaReader reader = new ColorSchemaReader();
+      Collection<ColorSchema> schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      LightLayoutReactionViewFactory factory = new LightLayoutReactionViewFactory();
+      List<LightLayoutReactionView> result = new ArrayList<>();
+      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
+        if (entry.getKey() instanceof Reaction) {
+          result.add(factory.create(new Pair<Reaction, ColorSchema>((Reaction) entry.getKey(), entry.getValue())));
+        }
+      }
+      return result;
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  @Override
+  public Map<Object, ColorSchema> getElementsForLayout(Model model, Integer layoutId, String token)
+      throws SecurityException {
+    try {
+      ColorSchemaReader reader = new ColorSchemaReader();
+      Collection<ColorSchema> schemas;
+      schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      return command.getModifiedElements();
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  @Override
+  public EmailSender getEmailSender() {
+    return emailSender;
+  }
+
+  @Override
+  public void setEmailSender(EmailSender emailSender) {
+    this.emailSender = emailSender;
+  }
+
+  @Override
+  public List<Layout> getCustomLayouts(Model model, String token, Boolean publicOverlay, User creator)
+      throws SecurityException {
+    User user = userService.getUserByToken(token);
+    List<Layout> result = new ArrayList<>();
+    if (model == null || user == null) {
+      return result;
+    }
+    List<Layout> overlays = layoutDao.getLayoutsByModel(model, creator, publicOverlay);
+    for (Layout overlay : overlays) {
+      if (userCanViewOverlay(overlay, user)) {
+        result.add(overlay);
+      }
+    }
+    Collections.sort(result, Layout.ID_COMPARATOR);
+    return result;
+  }
+
+  @Override
+  public Layout getLayoutById(int overlayId, String token) throws SecurityException {
+    Layout layout = layoutDao.getById(overlayId);
+    if (layout == null) {
+      return null;
+    }
+    User user = userService.getUserByToken(token);
+    if (!userCanViewOverlay(layout, user)) {
+      throw new SecurityException("User doesn't have access to overlay");
+    }
+    return layout;
+  }
+
+  @Override
+  public FullLayoutAliasView getFullAliasForLayout(Model model, Integer id, int layoutId, String token)
+      throws SecurityException {
+    try {
+      ColorSchemaReader reader = new ColorSchemaReader();
+      Collection<ColorSchema> schemas;
+      schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      FullLayoutAliasViewFactory factory = new FullLayoutAliasViewFactory();
+
+      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
+        if (entry.getKey() instanceof Element) {
+          Element alias = (Element) entry.getKey();
+          if (id.equals(alias.getId())) {
+            return factory.create(new Pair<Element, ColorSchema>(alias, entry.getValue()));
+          }
+        }
+      }
+      return null;
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  @Override
+  public FullLayoutReactionView getFullReactionForLayout(Model model, Integer id, int layoutId, String token)
+      throws SecurityException {
+    try {
+      ColorSchemaReader reader = new ColorSchemaReader();
+      Collection<ColorSchema> schemas;
+      schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      FullLayoutReactionViewFactory factory = new FullLayoutReactionViewFactory();
+
+      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
+        if (entry.getKey() instanceof Reaction) {
+          Reaction alias = (Reaction) entry.getKey();
+          if (id.equals(alias.getId())) {
+            return factory.create(new Pair<Reaction, ColorSchema>(alias, entry.getValue()));
+          }
+        }
+      }
+      return null;
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  @Override
+  public boolean userCanRemoveLayout(Layout layout, String authenticationToken) throws SecurityException {
+    User user = userService.getUserByToken(authenticationToken);
+    return userCanRemoveLayout(layout, user);
+  }
+}
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java
index 8ee8ed38a7440e9dabfe636d7744b6373abe3e3b..018939ca4bb57f9f9f0d2a00d978b78c13e02d97 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java
@@ -1,473 +1,494 @@
-package lcsb.mapviewer.services.interfaces;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-
-import lcsb.mapviewer.commands.CommandExecutionException;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
-import lcsb.mapviewer.model.map.layout.Layout;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.user.User;
-import lcsb.mapviewer.services.SecurityException;
-import lcsb.mapviewer.services.search.layout.FullLayoutAliasView;
-import lcsb.mapviewer.services.search.layout.FullLayoutReactionView;
-import lcsb.mapviewer.services.search.layout.LightLayoutAliasView;
-import lcsb.mapviewer.services.search.layout.LightLayoutReactionView;
-import lcsb.mapviewer.services.utils.EmailSender;
-import lcsb.mapviewer.services.utils.data.ColorSchemaType;
-
-/**
- * Service that manages layouts of the map.
- * 
- * @author Piotr Gawron
- * 
- */
-public interface ILayoutService {
-
-  /**
-   * Parameters used for creation of the layout.
-   * 
-   * @author Piotr Gawron
-   * 
-   */
-  class CreateLayoutParams {
-
-    /**
-     * Size of the buffer used to copy stream data.
-     */
-    private static final int BUFFER_SIZE = 1024;
-
-    /**
-     * Name of the layout.
-     * 
-     */
-    private String name;
-
-    /**
-     * Description of the layout.
-     * 
-     */
-    private String description;
-
-    /**
-     * Where the graphic files should be saved.
-     * 
-     */
-    private String directory;
-
-    /**
-     * 
-     * {@link Model} for which the layout is created.
-     */
-    private Model model;
-
-    /**
-     * Who creates the layout.
-     * 
-     */
-    private User user;
-
-    /**
-     * 
-     * Input stream with coloring information data in the stream should correspond
-     * to a file that can be parsed by
-     * {@link lcsb.mapviewer.services.utils.ColorSchemaXlsxReader ColorSchemaReader}
-     * . This is a copy of original input stream, so we can read this input stream
-     * multiple times.
-     */
-    private ByteArrayOutputStream colorInputStreamCopy;
-
-    /**
-     * Name of the file used as input (if available).
-     */
-    private String layoutFileName;
-
-    /**
-     * Determines if creation of the output files should be done asynchronously who
-     * creates the layout.
-     * 
-     */
-    private boolean async = false;
-
-    /**
-     * Type of the uploaded file.
-     */
-    private ColorSchemaType colorSchemaType;
-
-    /**
-     * @return the name
-     * @see #name
-     */
-    public String getName() {
-      return name;
-    }
-
-    /**
-     * @param name
-     *          the name to set
-     * @see #name
-     * @return {@link CreateLayoutParams} object
-     */
-    public CreateLayoutParams name(String name) {
-      this.name = name;
-      return this;
-    }
-
-    /**
-     * @return the directory
-     * @see #directory
-     */
-    public String getDirectory() {
-      return directory;
-    }
-
-    /**
-     * @param directory
-     *          the directory to set
-     * @see #directory
-     * @return {@link CreateLayoutParams} object
-     */
-    public CreateLayoutParams directory(String directory) {
-      this.directory = directory;
-      return this;
-    }
-
-    /**
-     * @return the model
-     * @see #model
-     */
-    public Model getModel() {
-      return model;
-    }
-
-    /**
-     * @param model
-     *          the model to set
-     * @see #model
-     * @return {@link CreateLayoutParams} object
-     */
-    public CreateLayoutParams model(Model model) {
-      this.model = model;
-      return this;
-    }
-
-    /**
-     * @return the user
-     * @see #user
-     */
-    public User getUser() {
-      return user;
-    }
-
-    /**
-     * @param user
-     *          the user to set
-     * @see #user
-     * @return {@link CreateLayoutParams} object
-     */
-    public CreateLayoutParams user(User user) {
-      this.user = user;
-      return this;
-    }
-
-    /**
-     * @return the colorInputStream
-     * @see #colorInputStream
-     */
-    public InputStream getColorInputStream() {
-      return new ByteArrayInputStream(colorInputStreamCopy.toByteArray());
-    }
-
-    /**
-     * @param colorInputStream
-     *          the colorInputStream to set
-     * @see #colorInputStream
-     * @return {@link CreateLayoutParams} object
-     * @throws IOException
-     *           thrown when there is a problem with accessing input stream
-     */
-    public CreateLayoutParams colorInputStream(InputStream colorInputStream) throws IOException {
-      if (colorInputStream == null) {
-        this.colorInputStreamCopy = null;
-      } else {
-        this.colorInputStreamCopy = new ByteArrayOutputStream();
-
-        byte[] buffer = new byte[BUFFER_SIZE];
-        int len;
-        while ((len = colorInputStream.read(buffer)) > -1) {
-          this.colorInputStreamCopy.write(buffer, 0, len);
-        }
-        this.colorInputStreamCopy.flush();
-      }
-      return this;
-    }
-
-    /**
-     * @return the async
-     * @see #async
-     */
-    public boolean isAsync() {
-      return async;
-    }
-
-    /**
-     * @param async
-     *          the async to set
-     * @see #async
-     * @return {@link CreateLayoutParams} object
-     */
-    public CreateLayoutParams async(boolean async) {
-      this.async = async;
-      return this;
-    }
-
-    /**
-     * @return the description
-     * @see #description
-     */
-    public String getDescription() {
-      return description;
-    }
-
-    /**
-     * @param description
-     *          the description to set
-     * @see #description
-     * @return {@link CreateLayoutParams} object
-     */
-    public CreateLayoutParams description(String description) {
-      this.description = description;
-      return this;
-    }
-
-    /**
-     * 
-     * @return {@link #colorSchemaType}
-     */
-    public ColorSchemaType getColorSchemaType() {
-      return colorSchemaType;
-    }
-
-    /**
-     * @param colorSchemaType
-     *          the colorSchemaType to set
-     * @see #colorSchemaType
-     * @return {@link CreateLayoutParams} object
-     */
-    public CreateLayoutParams colorSchemaType(ColorSchemaType colorSchemaType) {
-      this.colorSchemaType = colorSchemaType;
-      return this;
-    }
-
-    /**
-     * @return the layoutFileName
-     * @see #layoutFileName
-     */
-    public String getLayoutFileName() {
-      return layoutFileName;
-    }
-
-    /**
-     * @param layoutFileName
-     *          the layoutFileName to set
-     * @return {@link CreateLayoutParams} object
-     * @see #layoutFileName
-     */
-    public CreateLayoutParams layoutFileName(String layoutFileName) {
-      this.layoutFileName = layoutFileName;
-      return this;
-    }
-  }
-
-  /**
-   * Returns true if user can add layout to the model.
-   * 
-   * @param model
-   *          to which model user wants to add layout
-   * @param user
-   *          who wants to add layout
-   * @return <code>true</code> if user can add layout, <code>false</code>
-   *         otherwise
-   */
-  boolean userCanAddLayout(Model model, User user);
-
-  /**
-   * Returns true if user can remove layout from the model.
-   * 
-   * @param layout
-   *          which layout user want to remove
-   * @param user
-   *          who wants to remove layout
-   * @return <code>true</code> if user can remove layout, <code>false</code>
-   *         otherwise
-   */
-  boolean userCanRemoveLayout(Layout layout, User user);
-
-  /**
-   * Removes layout from the system.
-   * 
-   * @param layout
-   *          layout to remove
-   * @param homeDir
-   *          directory where the system is deployed
-   * @throws IOException
-   *           thrown when there are problems with removing layout files
-   */
-  void removeLayout(Layout layout, String homeDir) throws IOException;
-
-  /**
-   * Updates data about the layout.
-   * 
-   * @param layout
-   *          layout to update
-   */
-  void updateLayout(Layout layout);
-
-  /**
-   * Adds view privilege to the layout for the user.
-   * 
-   * @param layout
-   *          layout for privilege
-   * @param user
-   *          who should own the privilege
-   */
-  void addViewPrivilegeToLayout(Layout layout, User user);
-
-  /**
-   * Removes view privilege to the layout from the user.
-   * 
-   * @param layout
-   *          layout for privilege remove
-   * @param user
-   *          who shouldn't have the privilege
-   */
-  void dropViewPrivilegeFromLayout(Layout layout, User user);
-
-  /**
-   * Create layout based on the data in the parameter.
-   * 
-   * @param params
-   *          list of {@link CreateLayoutParams params} necessary to create layout
-   * @return object that refers to created layout
-   * @throws IOException
-   *           thrown when there are problems with files
-   * @throws InvalidColorSchemaException
-   *           if the coloring source is invalid
-   * @throws CommandExecutionException
-   */
-  Layout createLayout(CreateLayoutParams params) throws IOException, InvalidColorSchemaException;
-
-  /**
-   * Create layout based on the data in the parameter. Layout will contain set of
-   * images that can be further visualized in goolge maps api.
-   * 
-   * @param params
-   *          list of {@link CreateLayoutParams params} necessary to create layout
-   * @return object that refers to created layout
-   * @throws IOException
-   *           thrown when there are problems with files
-   * @throws CommandExecutionException
-   *           if the coloring source is invalid
-   * @throws InvalidColorSchemaException
-   *           if the coloring source is invalid
-   */
-  Layout createLayoutWithImages(CreateLayoutParams params)
-      throws IOException, CommandExecutionException, InvalidColorSchemaException;
-
-  /**
-   * Returns number of still available custom layouts for the user.
-   * 
-   * @param user
-   *          user for which the number of available custom layouts will be
-   *          returned
-   * @return number of available custom layouts
-   */
-  long getAvailableCustomLayoutsNumber(User user);
-
-  /**
-   * Returns a list of {@link LightLayoutAliasView aliases} that are visualized in
-   * a {@link lcsb.mapviewer.model.map.layout.Layout}.
-   * 
-   * @param model
-   *          model where data is located
-   * @param layoutId
-   *          identifier of the layout
-   * @return a list of {@link LightLayoutAliasView aliases} that are visualized in
-   *         a {@link lcsb.mapviewer.model.map.layout.Layout}
-   * @throws SecurityException
-   */
-  List<LightLayoutAliasView> getAliasesForLayout(Model model, int layoutId, String token) throws SecurityException;
-
-  /**
-   * Returns a list of {@link LightLayoutReactionView reactions} that are
-   * visualized in a {@link lcsb.mapviewer.model.map.layout.Layout}.
-   * 
-   * @param model
-   *          model where data is located
-   * @param layoutId
-   *          identifier of the layout
-   * @return a list of {@link LightLayoutReactionView reactions} that are
-   *         visualized in a {@link lcsb.mapviewer.model.map.layout.Layout}
-   * @throws SecurityException
-   */
-  List<LightLayoutReactionView> getReactionsForLayout(Model model, int layoutId, String token) throws SecurityException;
-
-  /**
-   * Returns mapping between {@link lcsb.mapviewer.model.map.species.Element
-   * Alias}/ {@link lcsb.mapviewer.model.map.reaction.Reaction Reaction} and
-   * {@link ColorSchema} used for coloring object in the layout given in the
-   * parameter.
-   * 
-   * @param model
-   *          model where data is located
-   * @param layoutId
-   *          identifier of the layout
-   * @return a list of {@link LightLayoutReactionView reactions} that are
-   *         visualized in a {@link lcsb.mapviewer.model.map.layout.Layout}
-   * @throws SecurityException
-   */
-  Map<Object, ColorSchema> getElementsForLayout(Model model, Integer layoutId, String token) throws SecurityException;
-
-  FullLayoutAliasView getFullAliasForLayout(Model model, Integer id, int layoutId, String token)
-      throws SecurityException;
-
-  FullLayoutReactionView getFullReactionForLayout(Model model, Integer id, int layoutId, String token)
-      throws SecurityException;
-
-  /**
-   * Returns {@link EmailSender} used by the service.
-   * 
-   * @return {@link EmailSender} used by the service
-   */
-  EmailSender getEmailSender();
-
-  /**
-   * Sets {@link EmailSender} used by the service.
-   * 
-   * @param emailSender
-   *          {@link EmailSender} used by the service
-   */
-  void setEmailSender(EmailSender emailSender);
-
-  /**
-   * Returns list of custom layouts.
-   * 
-   * @param model
-   *          model where the layouts lay on
-   * @param user
-   *          user who asks for the layouts
-   * @return list of custom layouts
-   */
-  List<Layout> getCustomLayouts(Model model, String token, Boolean publicOverlay, User creator)
-      throws SecurityException;
-
-  Layout getLayoutById(int overlayId, String token) throws SecurityException;
-
-  boolean userCanRemoveLayout(Layout layout, String authenticationToken) throws SecurityException;
-
-}
+package lcsb.mapviewer.services.interfaces;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import lcsb.mapviewer.commands.CommandExecutionException;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
+import lcsb.mapviewer.model.map.layout.Layout;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.services.SecurityException;
+import lcsb.mapviewer.services.search.layout.FullLayoutAliasView;
+import lcsb.mapviewer.services.search.layout.FullLayoutReactionView;
+import lcsb.mapviewer.services.search.layout.LightLayoutAliasView;
+import lcsb.mapviewer.services.search.layout.LightLayoutReactionView;
+import lcsb.mapviewer.services.utils.EmailSender;
+import lcsb.mapviewer.services.utils.data.ColorSchemaType;
+
+/**
+ * Service that manages layouts of the map.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public interface ILayoutService {
+
+  /**
+   * Parameters used for creation of the layout.
+   *
+   * @author Piotr Gawron
+   *
+   */
+  class CreateLayoutParams {
+
+    /**
+     * Size of the buffer used to copy stream data.
+     */
+    private static final int BUFFER_SIZE = 1024;
+
+    /**
+     * Name of the layout.
+     *
+     */
+    private String name;
+
+    /**
+     * Description of the layout.
+     *
+     */
+    private String description;
+
+    /**
+     * Where the graphic files should be saved.
+     *
+     */
+    private String directory;
+
+    /**
+     *
+     * {@link Model} for which the layout is created.
+     */
+    private Model model;
+
+    /**
+     * Who creates the layout.
+     *
+     */
+    private User user;
+
+    /**
+     *
+     * Input stream with coloring information data in the stream should correspond
+     * to a file that can be parsed by
+     * {@link lcsb.mapviewer.services.utils.ColorSchemaXlsxReader ColorSchemaReader}
+     * . This is a copy of original input stream, so we can read this input stream
+     * multiple times.
+     */
+    private ByteArrayOutputStream colorInputStreamCopy;
+
+    /**
+     * Name of the file used as input (if available).
+     */
+    private String layoutFileName;
+
+    /**
+     * Determines if creation of the output files should be done asynchronously who
+     * creates the layout.
+     *
+     */
+    private boolean async = false;
+
+        private boolean                             googleLicenseConsent               = false;
+
+    /**
+     * Type of the uploaded file.
+     */
+    private ColorSchemaType colorSchemaType;
+
+    /**
+     * @return the name
+     * @see #name
+     */
+    public String getName() {
+      return name;
+    }
+
+    /**
+     * @param name
+     *          the name to set
+     * @see #name
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams name(String name) {
+      this.name = name;
+      return this;
+    }
+
+    /**
+     * @return the directory
+     * @see #directory
+     */
+    public String getDirectory() {
+      return directory;
+    }
+
+    /**
+     * @param directory
+     *          the directory to set
+     * @see #directory
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams directory(String directory) {
+      this.directory = directory;
+      return this;
+    }
+
+    /**
+     * @return the model
+     * @see #model
+     */
+    public Model getModel() {
+      return model;
+    }
+
+    /**
+     * @param model
+     *          the model to set
+     * @see #model
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams model(Model model) {
+      this.model = model;
+      return this;
+    }
+
+    /**
+     * @return the user
+     * @see #user
+     */
+    public User getUser() {
+      return user;
+    }
+
+    /**
+     * @param user
+     *          the user to set
+     * @see #user
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams user(User user) {
+      this.user = user;
+      return this;
+    }
+
+    /**
+     * @return the colorInputStream
+     * @see #colorInputStream
+     */
+    public InputStream getColorInputStream() {
+      return new ByteArrayInputStream(colorInputStreamCopy.toByteArray());
+    }
+
+    /**
+     * @param colorInputStream
+     *          the colorInputStream to set
+     * @see #colorInputStream
+     * @return {@link CreateLayoutParams} object
+     * @throws IOException
+     *           thrown when there is a problem with accessing input stream
+     */
+    public CreateLayoutParams colorInputStream(InputStream colorInputStream) throws IOException {
+      if (colorInputStream == null) {
+        this.colorInputStreamCopy = null;
+      } else {
+        this.colorInputStreamCopy = new ByteArrayOutputStream();
+
+        byte[] buffer = new byte[BUFFER_SIZE];
+        int len;
+        while ((len = colorInputStream.read(buffer)) > -1) {
+          this.colorInputStreamCopy.write(buffer, 0, len);
+        }
+        this.colorInputStreamCopy.flush();
+      }
+      return this;
+    }
+
+    /**
+     * @return the async
+     * @see #async
+     */
+    public boolean isAsync() {
+      return async;
+    }
+
+    /**
+     * @param async
+     *          the async to set
+     * @see #async
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams async(boolean async) {
+      this.async = async;
+      return this;
+    }
+
+    /**
+     * @return the googleLicenseConsent
+     * @see #googleLicenseConsent
+     */
+    public boolean isGoogleLicenseConsent() {
+        return googleLicenseConsent;
+    }
+
+    /**
+     * @param googleLicenseConsent
+     *          the googleLicenseConsent to set
+     * @see #googleLicenseConsent
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams googleLicenseConsent(boolean googleLicenseConsent) {
+       this.googleLicenseConsent = googleLicenseConsent;
+       return this;
+    }
+
+    /**
+     * @return the description
+     * @see #description
+     */
+    public String getDescription() {
+      return description;
+    }
+
+    /**
+     * @param description
+     *          the description to set
+     * @see #description
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams description(String description) {
+      this.description = description;
+      return this;
+    }
+
+    /**
+     *
+     * @return {@link #colorSchemaType}
+     */
+    public ColorSchemaType getColorSchemaType() {
+      return colorSchemaType;
+    }
+
+    /**
+     * @param colorSchemaType
+     *          the colorSchemaType to set
+     * @see #colorSchemaType
+     * @return {@link CreateLayoutParams} object
+     */
+    public CreateLayoutParams colorSchemaType(ColorSchemaType colorSchemaType) {
+      this.colorSchemaType = colorSchemaType;
+      return this;
+    }
+
+    /**
+     * @return the layoutFileName
+     * @see #layoutFileName
+     */
+    public String getLayoutFileName() {
+      return layoutFileName;
+    }
+
+    /**
+     * @param layoutFileName
+     *          the layoutFileName to set
+     * @return {@link CreateLayoutParams} object
+     * @see #layoutFileName
+     */
+    public CreateLayoutParams layoutFileName(String layoutFileName) {
+      this.layoutFileName = layoutFileName;
+      return this;
+    }
+  }
+
+  /**
+   * Returns true if user can add layout to the model.
+   *
+   * @param model
+   *          to which model user wants to add layout
+   * @param user
+   *          who wants to add layout
+   * @return <code>true</code> if user can add layout, <code>false</code>
+   *         otherwise
+   */
+  boolean userCanAddLayout(Model model, User user);
+
+  /**
+   * Returns true if user can remove layout from the model.
+   *
+   * @param layout
+   *          which layout user want to remove
+   * @param user
+   *          who wants to remove layout
+   * @return <code>true</code> if user can remove layout, <code>false</code>
+   *         otherwise
+   */
+  boolean userCanRemoveLayout(Layout layout, User user);
+
+  /**
+   * Removes layout from the system.
+   *
+   * @param layout
+   *          layout to remove
+   * @param homeDir
+   *          directory where the system is deployed
+   * @throws IOException
+   *           thrown when there are problems with removing layout files
+   */
+  void removeLayout(Layout layout, String homeDir) throws IOException;
+
+  /**
+   * Updates data about the layout.
+   *
+   * @param layout
+   *          layout to update
+   */
+  void updateLayout(Layout layout);
+
+  /**
+   * Adds view privilege to the layout for the user.
+   *
+   * @param layout
+   *          layout for privilege
+   * @param user
+   *          who should own the privilege
+   */
+  void addViewPrivilegeToLayout(Layout layout, User user);
+
+  /**
+   * Removes view privilege to the layout from the user.
+   *
+   * @param layout
+   *          layout for privilege remove
+   * @param user
+   *          who shouldn't have the privilege
+   */
+  void dropViewPrivilegeFromLayout(Layout layout, User user);
+
+  /**
+   * Create layout based on the data in the parameter.
+   *
+   * @param params
+   *          list of {@link CreateLayoutParams params} necessary to create layout
+   * @return object that refers to created layout
+   * @throws IOException
+   *           thrown when there are problems with files
+   * @throws InvalidColorSchemaException
+   *           if the coloring source is invalid
+   * @throws CommandExecutionException
+   */
+  Layout createLayout(CreateLayoutParams params) throws IOException, InvalidColorSchemaException;
+
+  /**
+   * Create layout based on the data in the parameter. Layout will contain set of
+   * images that can be further visualized in goolge maps api.
+   *
+   * @param params
+   *          list of {@link CreateLayoutParams params} necessary to create layout
+   * @return object that refers to created layout
+   * @throws IOException
+   *           thrown when there are problems with files
+   * @throws CommandExecutionException
+   *           if the coloring source is invalid
+   * @throws InvalidColorSchemaException
+   *           if the coloring source is invalid
+   */
+  Layout createLayoutWithImages(CreateLayoutParams params)
+      throws IOException, CommandExecutionException, InvalidColorSchemaException;
+
+  /**
+   * Returns number of still available custom layouts for the user.
+   *
+   * @param user
+   *          user for which the number of available custom layouts will be
+   *          returned
+   * @return number of available custom layouts
+   */
+  long getAvailableCustomLayoutsNumber(User user);
+
+  /**
+   * Returns a list of {@link LightLayoutAliasView aliases} that are visualized in
+   * a {@link lcsb.mapviewer.model.map.layout.Layout}.
+   *
+   * @param model
+   *          model where data is located
+   * @param layoutId
+   *          identifier of the layout
+   * @return a list of {@link LightLayoutAliasView aliases} that are visualized in
+   *         a {@link lcsb.mapviewer.model.map.layout.Layout}
+   * @throws SecurityException
+   */
+  List<LightLayoutAliasView> getAliasesForLayout(Model model, int layoutId, String token) throws SecurityException;
+
+  /**
+   * Returns a list of {@link LightLayoutReactionView reactions} that are
+   * visualized in a {@link lcsb.mapviewer.model.map.layout.Layout}.
+   *
+   * @param model
+   *          model where data is located
+   * @param layoutId
+   *          identifier of the layout
+   * @return a list of {@link LightLayoutReactionView reactions} that are
+   *         visualized in a {@link lcsb.mapviewer.model.map.layout.Layout}
+   * @throws SecurityException
+   */
+  List<LightLayoutReactionView> getReactionsForLayout(Model model, int layoutId, String token) throws SecurityException;
+
+  /**
+   * Returns mapping between {@link lcsb.mapviewer.model.map.species.Element
+   * Alias}/ {@link lcsb.mapviewer.model.map.reaction.Reaction Reaction} and
+   * {@link ColorSchema} used for coloring object in the layout given in the
+   * parameter.
+   *
+   * @param model
+   *          model where data is located
+   * @param layoutId
+   *          identifier of the layout
+   * @return a list of {@link LightLayoutReactionView reactions} that are
+   *         visualized in a {@link lcsb.mapviewer.model.map.layout.Layout}
+   * @throws SecurityException
+   */
+  Map<Object, ColorSchema> getElementsForLayout(Model model, Integer layoutId, String token) throws SecurityException;
+
+  FullLayoutAliasView getFullAliasForLayout(Model model, Integer id, int layoutId, String token)
+      throws SecurityException;
+
+  FullLayoutReactionView getFullReactionForLayout(Model model, Integer id, int layoutId, String token)
+      throws SecurityException;
+
+  /**
+   * Returns {@link EmailSender} used by the service.
+   *
+   * @return {@link EmailSender} used by the service
+   */
+  EmailSender getEmailSender();
+
+  /**
+   * Sets {@link EmailSender} used by the service.
+   *
+   * @param emailSender
+   *          {@link EmailSender} used by the service
+   */
+  void setEmailSender(EmailSender emailSender);
+
+  /**
+   * Returns list of custom layouts.
+   *
+   * @param model
+   *          model where the layouts lay on
+   * @param user
+   *          user who asks for the layouts
+   * @return list of custom layouts
+   */
+  List<Layout> getCustomLayouts(Model model, String token, Boolean publicOverlay, User creator)
+      throws SecurityException;
+
+  Layout getLayoutById(int overlayId, String token) throws SecurityException;
+
+  boolean userCanRemoveLayout(Layout layout, String authenticationToken) throws SecurityException;
+
+}
diff --git a/web/src/main/webapp/index.xhtml b/web/src/main/webapp/index.xhtml
index 87b3437924fdbf96cee1613a7a1c06f6354487b4..385a0661cc00cc1b9b47dab145170db49ddc30e8 100644
--- a/web/src/main/webapp/index.xhtml
+++ b/web/src/main/webapp/index.xhtml
@@ -10,9 +10,6 @@
 
  
 <h:head>
-	
-	<!-- Google Maps API version 3.20	-->
-	<script src="https://maps.google.com/maps/api/js?libraries=drawing" type="text/javascript"/>
 
 	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" type="text/javascript"/>
 	<script src="https://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.min.js" type="text/javascript"/>
@@ -20,12 +17,12 @@
   <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
   <script src="https://cdn.datatables.net/1.10.13/js/jquery.dataTables.min.js"></script>
   <script src="https://cdn.datatables.net/rowreorder/1.2.3/js/dataTables.rowReorder.min.js"></script>
-  
+
 
 	<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.13/css/jquery.dataTables.min.css"/>	
 	<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"/>
 	<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/rowreorder/1.2.3/css/rowReorder.dataTables.min.css"/>
-	
+
 	<link rel="shortcut icon" href="./resources/images/favicon.png" type="image/png" />
 
 	<h:outputScript library="js" name="minerva.js"  />
diff --git a/web/src/main/webapp/login.xhtml b/web/src/main/webapp/login.xhtml
index af2062f2a1a49b216dd87cd5af4fccbdec895add..918f7b88217a0bdea2ae8e0d4b2d04d297e1e043 100644
--- a/web/src/main/webapp/login.xhtml
+++ b/web/src/main/webapp/login.xhtml
@@ -11,10 +11,6 @@
 	<link rel="shortcut icon" href="./resources/images/favicon.png"
 		type="image/png" />
 
-	<script
-		src="https://maps.google.com/maps/api/js?libraries=drawing&amp;v=3.26"
-		type="text/javascript" />
-
 
 	<script src="https://code.jquery.com/jquery-1.12.1.min.js"></script>
 	<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
@@ -36,7 +32,7 @@
 		function init() {
 			var element = document.getElementById('minervaAppDiv');
 			  return minerva.createLogin({
-					element : element, 
+					element : element,
 				}).catch(function(rejectReason){
 					minerva.GuiConnector.alert(rejectReason, true);
 				});