diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index c6df9c7c99481ffb3a9bb6c6d65fe61878a2c4d8..3c2213a19f51780e9ee49f1a2ec5cfe540dc3338 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -11,6 +11,7 @@ var request = require('request');
 var HttpStatus = require('http-status-codes');
 
 var Alias = require('./map/data/Alias');
+var Annotation = require('./map/data/Annotation');
 var Chemical = require('./map/data/Chemical');
 var Comment = require('./map/data/Comment');
 var Configuration = require('./Configuration');
@@ -40,23 +41,51 @@ var ObjectWithListeners = require('./ObjectWithListeners');
  * This object contains methods that will communicate with server.
  */
 var ServerConnector = new ObjectWithListeners();
-ServerConnector.registerListenerType("onDataLoadStart");
-ServerConnector.registerListenerType("onDataLoadStop");
+ServerConnector.init = function () {
+  var self = this;
 
-ServerConnector._configurationParam = [];
-ServerConnector._serverBaseUrl= undefined;
+  self._configurationParam = [];
+  self._projects = [];
+  self._projectsById = [];
 
+  self._users = [];
+  self._usersByLogin = [];
+
+  self._customMap = null;
+  self._sessionData = undefined;
+  self._configuration = undefined;
+  self._loggedUser = undefined;
+  self._serverBaseUrl = undefined;
+
+  var i;
+  var listeners = self.getListeners("onDataLoadStart");
+  for (i = 0; i < listeners.length; i++) {
+    self.removeListener("onDataLoadStart", listeners[i]);
+  }
+
+  listeners = self.getListeners("onDataLoadStop");
+  for (i = 0; i < listeners.length; i++) {
+    self.removeListener("onDataLoadStop", listeners[i]);
+  }
+
+};
+ServerConnector.registerListenerType("onDataLoadStart");
+ServerConnector.registerListenerType("onDataLoadStop");
+ServerConnector.init();
 
 ServerConnector.getMinOverlayColorInt = function () {
   var self = this;
-  var userColor;
   return self.getLoggedUser().then(function (user) {
-    userColor = user.getMinColor();
-    return self.getConfigurationParam(ConfigurationType.MIN_COLOR_VAL);
-  }).then(function (systemMinColor) {
+    var userColor = user.getMinColor();
+    return self.returnUserOrSystemColor(userColor, self.getConfigurationParam(ConfigurationType.MIN_COLOR_VAL));
+  });
+};
+
+ServerConnector.returnUserOrSystemColor = function (userColor, systemPromisedColor) {
+  return systemPromisedColor.then(function (systemColor) {
     var color = userColor;
     if (userColor === null || userColor === undefined || userColor === "") {
-      color = systemMinColor;
+      color = systemColor;
     }
     color = parseInt(color, 16);
     /* jslint bitwise: true */
@@ -67,54 +96,48 @@ ServerConnector.getMinOverlayColorInt = function () {
 
 ServerConnector.getSimpleOverlayColorInt = function () {
   var self = this;
-  var userColor;
   return self.getLoggedUser().then(function (user) {
-    userColor = user.getSimpleColor();
-    return self.getConfigurationParam(ConfigurationType.SIMPLE_COLOR_VAL);
-  }).then(function (systemSimpleColor) {
-    var color = userColor;
-    if (userColor === null || userColor === undefined || userColor === "") {
-      color = systemSimpleColor;
-    }
-    color = parseInt(color, 16);
-    /* jslint bitwise: true */
-    color = (color & 0xFFFFFF);
-    return color;
+    var userColor = user.getSimpleColor();
+    return self.returnUserOrSystemColor(userColor, self.getConfigurationParam(ConfigurationType.SIMPLE_COLOR_VAL));
   });
 };
 
 ServerConnector.getMaxOverlayColorInt = function () {
   var self = this;
-  var userColor;
   return self.getLoggedUser().then(function (user) {
-    userColor = user.getMaxColor();
-    return self.getConfigurationParam(ConfigurationType.MAX_COLOR_VAL);
-  }).then(function (systemMaxColor) {
-    var color = userColor;
-    if (userColor === null || userColor === undefined || userColor === "") {
-      color = systemMaxColor;
-    }
-    color = parseInt(color, 16);
-    /* jslint bitwise: true */
-    color = (color & 0xFFFFFF);
-    return color;
+    var userColor = user.getMaxColor();
+    return self.returnUserOrSystemColor(userColor, self.getConfigurationParam(ConfigurationType.MAX_COLOR_VAL));
+  });
+};
+
+ServerConnector.sendGetRequest = function (url, description) {
+  return this.sendRequest({
+    url: url,
+    description: description,
+    method: "GET"
   });
 };
 
-ServerConnector.readFile = function (url, description) {
+ServerConnector.sendRequest = function (params) {
   var self = this;
+  if (arguments.length > 1) {
+    return Promise.reject(new Error("Only two arguments are supported"));
+  }
 
   if (self.getSessionData().getToken() === undefined) {
     self.getSessionData().setLogin(undefined);
     window.location.reload(false);
   }
 
-  if (description === undefined) {
-    description = url;
+  var description = params.url;
+  if (params.description !== undefined) {
+    description = params.description;
+    params.description = undefined;
   }
+
   var content;
   return self.callListeners("onDataLoadStart", description).then(function () {
-    return self._readFile(url);
+    return self._sendRequest(params);
   }).then(function (result) {
     content = result;
     return self.callListeners("onDataLoadStop", description);
@@ -125,132 +148,64 @@ ServerConnector.readFile = function (url, description) {
   }).then(function () {
     return content;
   });
-};
 
-ServerConnector._readFile = function (url) {
-  return new Promise(function (resolve, reject) {
-    request.get(url, function (error, response, body) {
-      if (error) {
-        reject(error);
-      } else if (response.statusCode !== 200) {
-        reject(new NetworkError(url + " rejected with status code: " + response.statusCode, {
-          content: body,
-          url: url,
-          statusCode: response.statusCode
-        }));
-      } else {
-        resolve(body);
-      }
-    });
-  });
 };
 
-ServerConnector.sendPostRequest = function (url, params) {
-  var self = this;
-  if (self.getSessionData().getToken() === undefined) {
-    self.getSessionData().setLogin(undefined);
-    window.location.reload(false);
-  }
+ServerConnector._sendRequest = function (params) {
   return new Promise(function (resolve, reject) {
-    request.post({
-      url: url,
-      form: params
-    }, function (error, response, body) {
+    request(params, function (error, response, body) {
       if (error) {
         reject(new NetworkError(error.message, {
           content: body,
           url: url
         }));
-
       } else if (response.statusCode !== 200) {
-        reject(new NetworkError(url + " rejected with status code: " + response.statusCode, {
+        reject(new NetworkError(params.url + " rejected with status code: " + response.statusCode, {
           content: body,
-          url: url,
+          url: params.url,
           statusCode: response.statusCode
         }));
       } else {
-        resolve(body);
+        // for some reason sometimes result is an object not a string
+        if (typeof body === 'string' || body instanceof String) {
+          resolve(body);
+        } else {
+          resolve(JSON.stringify(body));
+        }
       }
     });
   });
 };
 
-ServerConnector.sendPutRequest = function (url, params) {
-  var self = this;
-  if (self.getSessionData().getToken() === undefined) {
-    self.getSessionData().setLogin(undefined);
-    window.location.reload(false);
-  }
-  return new Promise(function (resolve, reject) {
-    request.put({
-      url: url,
-      form: params
-    }, function (error, response, body) {
-      if (error) {
-        reject(error);
-      } else if (response.statusCode !== 200) {
-        reject(new Error(url + " rejected with status code: " + response.statusCode));
-      } else {
-        resolve(body);
-      }
-    });
+ServerConnector.sendPostRequest = function (url, params) {
+  return this.sendRequest({
+    method: "POST",
+    url: url,
+    form: params
   });
 };
 
-ServerConnector.sendDeleteRequest = function (url, params) {
-  var self = this;
-  if (self.getSessionData().getToken() === undefined) {
-    self.getSessionData().setLogin(undefined);
-    window.location.reload(false);
-  }
-  return new Promise(function (resolve, reject) {
-    request({
-      method: "DELETE",
-      url: url,
-      json: params,
-    }, function (error, response, body) {
-      if (error) {
-        reject(error);
-      } else if (response.statusCode !== 200) {
-        reject(new Error(url + " rejected with status code: " + response.statusCode));
-      } else {
-        resolve(body);
-      }
-    });
+ServerConnector.sendDeleteRequest = function (url, json) {
+  return this.sendRequest({
+    method: "DELETE",
+    url: url,
+    json: json
   });
 };
 
-ServerConnector.sendPatchRequest = function (url, params) {
-  var self = this;
-  if (self.getSessionData().getToken() === undefined) {
-    self.getSessionData().setLogin(undefined);
-    window.location.reload(false);
-  }
-  return new Promise(function (resolve, reject) {
-    request({
-      method: "PATCH",
-      url: url,
-      json: params,
-    }, function (error, response, body) {
-      if (error) {
-        reject(error);
-      } else if (response.statusCode !== 200) {
-        reject(new Error(url + " rejected with status code: " + response.statusCode));
-      } else {
-        resolve(body);
-      }
-    });
+ServerConnector.sendPatchRequest = function (url, json) {
+  return this.sendRequest({
+    method: "PATCH",
+    url: url,
+    json: json
   });
 };
 
-ServerConnector.getToken = function (token) {
-  if (token !== undefined) {
-    return Promise.resolve(token);
-  }
-
+ServerConnector.getToken = function () {
   var self = this;
-  token = self.getSessionData(null).getToken();
-  var login = self.getSessionData(null).getLogin()
+
+  var login = self.getSessionData(null).getLogin();
+  var token = self.getSessionData(null).getToken();
   if (token === undefined || login === undefined) {
     return self.login();
   } else {
@@ -259,6 +214,8 @@ ServerConnector.getToken = function (token) {
     if (self.getSessionData().getProject() === null) {
       return self.getConfiguration().then(function () {
         return token;
+        // if there was an error accessing configuration it means our token is
+        // invalid
       }, function () {
         return self.login();
       });
@@ -275,8 +232,8 @@ ServerConnector.getApiBaseUrl = function () {
 ServerConnector.getServerBaseUrl = function () {
   if (this._serverBaseUrl === undefined) {
     var url = "" + window.location.href;
-    if (url.indexOf("?")>=0) {
-      url = url.substr(0,url.indexOf("?"));
+    if (url.indexOf("?") >= 0) {
+      url = url.substr(0, url.indexOf("?"));
     }
     if (!url.endsWith("/")) {
       url = url.substr(0, url.lastIndexOf("/") + 1);
@@ -324,16 +281,12 @@ ServerConnector.createGetParams = function (params, prefix) {
 
 ServerConnector.getApiUrl = function (paramObj) {
   var type = paramObj.type;
-  var method = paramObj.method;
   var params = this.createGetParams(paramObj.params);
 
   var result = paramObj.url;
   if (result === undefined) {
     result = this.getApiBaseUrl() + "/" + type;
   }
-  if (method !== undefined) {
-    result += "/" + method;
-  }
   if (params !== "") {
     result += "?" + params;
   }
@@ -342,32 +295,23 @@ ServerConnector.getApiUrl = function (paramObj) {
 
 ServerConnector.getProjectsUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    type: "projects/" + queryParams.projectId + "/",
+    type: "projects/",
     params: filterParams,
-=======
-    type : "projects/",
-    params : filterParams,
   });
 };
 
-ServerConnector.getProjectUrl = function(queryParams, filterParams) {
+ServerConnector.getProjectUrl = function (queryParams, filterParams) {
+  var id = this.getIdOrAsterisk(queryParams.projectId);
   return this.getApiUrl({
-    url : this.getProjectsUrl(queryParams) + queryParams.projectId + "/",
-    params : filterParams,
->>>>>>> list of available projects
+    url: this.getProjectsUrl(queryParams) + id + "/",
+    params: filterParams,
   });
 };
 
 ServerConnector.getProjectStatisticsUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    url: this.getProjectsUrl(queryParams) + "statistics/",
+    url: this.getProjectUrl(queryParams) + "statistics/",
     params: filterParams,
-=======
-    url : this.getProjectUrl(queryParams) + "statistics/",
-    params : filterParams,
->>>>>>> list of available projects
   });
 };
 
@@ -406,7 +350,7 @@ ServerConnector.logoutUrl = function () {
 ServerConnector.getSuggestedQueryListUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
     url: this.getBioEntitiesUrl(queryParams) + "suggestedQueryList/",
-    params: filterParams,
+    params: filterParams
   });
 };
 
@@ -430,19 +374,20 @@ ServerConnector.updateOverlayUrl = function (queryParams) {
 
 ServerConnector.deleteOverlayUrl = function (queryParams) {
   return this.getApiUrl({
-    url: this.getOverlayByIdUrl(queryParams),
+    url: this.getOverlayByIdUrl(queryParams)
+  });
+};
+
+ServerConnector.deleteCommentUrl = function (queryParams) {
+  return this.getApiUrl({
+    url: this.getProjectUrl(queryParams) + "comments/" + queryParams.commentId + "/",
   });
 };
 
 ServerConnector.getOverlaysUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    url: this.getProjectsUrl(queryParams) + "overlays/",
+    url: this.getProjectUrl(queryParams) + "overlays/",
     params: filterParams,
-=======
-    url : this.getProjectUrl(queryParams) + "overlays/",
-    params : filterParams,
->>>>>>> list of available projects
   });
 };
 
@@ -496,7 +441,11 @@ ServerConnector.idsToString = function (ids) {
   var result = "";
   if (ids !== undefined) {
     ids.sort(function (a, b) {
-      return a - b;
+      if (typeof a === "string") {
+        return a.localeCompare(b);
+      } else {
+        return a - b;
+      }
     });
     for (var i = 0; i < ids.length; i++) {
       if (result !== "") {
@@ -515,13 +464,6 @@ ServerConnector.pointToString = function (point) {
   return point.x.toFixed(2) + "," + point.y.toFixed(2);
 };
 
-ServerConnector.columnsToString = function (columns) {
-  if (columns === undefined) {
-    return "";
-  }
-  return columns;
-};
-
 ServerConnector.getModelsUrl = function (queryParams) {
   var modelId = this.getIdOrAsterisk(queryParams.modelId);
   var overlayId = queryParams.overlayId;
@@ -552,65 +494,58 @@ ServerConnector.getIdOrAsterisk = function (id) {
 ServerConnector.getReactionsUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
     url: this.getBioEntitiesUrl(queryParams) + "reactions/",
-    params: filterParams,
+    params: filterParams
   });
 };
 
 ServerConnector.getAliasesUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
     url: this.getBioEntitiesUrl(queryParams) + "elements/",
-    params: filterParams,
+    params: filterParams
   });
 };
 
 ServerConnector.getConfigurationUrl = function (queryParams, filterParams) {
-  var result = this.getApiUrl({
+  return this.getApiUrl({
     type: "configuration/",
     params: filterParams
   });
-  return result;
 };
 
+ServerConnector.getConfigurationOptionUrl = function (queryParams, filterParams) {
+  var self = this;
+  return self.getApiUrl({
+    url: self.getConfigurationUrl() + "options/" + queryParams.type,
+    params: filterParams
+  });
+};
+
+
 ServerConnector.getSearchUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
     url: this.getModelsUrl(queryParams) + "bioEntities:search",
-    params: filterParams,
+    params: filterParams
   });
 };
 
 ServerConnector.getSearchDrugsUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    url: this.getProjectsUrl(queryParams) + "drugs:search",
+    url: this.getProjectUrl(queryParams) + "drugs:search",
     params: filterParams,
-=======
-    url : this.getProjectUrl(queryParams) + "drugs:search",
-    params : filterParams,
->>>>>>> list of available projects
   });
 };
 
 ServerConnector.getSearchMiRnasUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    url: this.getProjectsUrl(queryParams) + "miRnas:search",
+    url: this.getProjectUrl(queryParams) + "miRnas:search",
     params: filterParams,
-=======
-    url : this.getProjectUrl(queryParams) + "miRnas:search",
-    params : filterParams,
->>>>>>> list of available projects
   });
 };
 
 ServerConnector.getSearchChemicalsUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    url: this.getProjectsUrl(queryParams) + "chemicals:search",
+    url: this.getProjectUrl(queryParams) + "chemicals:search",
     params: filterParams,
-=======
-    url : this.getProjectUrl(queryParams) + "chemicals:search",
-    params : filterParams,
->>>>>>> list of available projects
   });
 };
 
@@ -623,25 +558,15 @@ ServerConnector.getOverlaySourceUrl = function (queryParams, filterParams) {
 
 ServerConnector.getImageUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    url: this.getProjectsUrl(queryParams) + "models/" + queryParams.modelId + ":downloadImage",
+    url: this.getProjectUrl(queryParams) + "models/" + queryParams.modelId + ":downloadImage",
     params: filterParams,
-=======
-    url : this.getProjectUrl(queryParams) + "models/" + queryParams.modelId + ":downloadImage",
-    params : filterParams,
->>>>>>> list of available projects
   });
 };
 
 ServerConnector.getModelPartUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    url: this.getProjectsUrl(queryParams) + "models/" + queryParams.modelId + ":downloadModel",
+    url: this.getProjectUrl(queryParams) + "models/" + queryParams.modelId + ":downloadModel",
     params: filterParams,
-=======
-    url : this.getProjectUrl(queryParams) + "models/" + queryParams.modelId + ":downloadModel",
-    params : filterParams,
->>>>>>> list of available projects
   });
 };
 
@@ -652,18 +577,61 @@ ServerConnector.getProjectSourceUrl = function (queryParams, filterParams) {
   });
 };
 
-ServerConnector.getUserUrl = function (queryParams, filterParams) {
+
+ServerConnector.getFilesUrl = function () {
+  return this.getApiUrl({
+    type: "files/"
+  });
+};
+
+ServerConnector.getCreateFileUrl = function () {
+  return this.getApiUrl({
+    url: this.getFilesUrl()
+  });
+};
+ServerConnector.getFileUrl = function (queryParams) {
+  return this.getApiUrl({
+    url: this.getFilesUrl() + "/" + queryParams.id
+  });
+};
+ServerConnector.getUploadFileUrl = function (queryParams) {
+  return this.getApiUrl({
+    url: this.getFileUrl(queryParams) + ":uploadContent"
+  });
+};
+
+
+ServerConnector.getUsersUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
     type: "users/",
-    method: queryParams.login,
+    params: filterParams
+  });
+};
+
+ServerConnector.getUserUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    url: this.getUsersUrl() + queryParams.login,
     params: filterParams,
   });
 };
 
+ServerConnector.getUpdateUserPrivilegesUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    url: this.getUserUrl(queryParams) + ":updatePrivileges",
+    params: filterParams,
+  });
+};
+ServerConnector.getUpdateUserPreferencesUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    url: this.getUserUrl(queryParams) + ":updatePreferences",
+    params: filterParams
+  });
+};
+
 ServerConnector.getConfiguration = function () {
   var self = this;
   if (this._configuration === undefined) {
-    return self.readFile(self.getConfigurationUrl()).then(function (content) {
+    return self.sendGetRequest(self.getConfigurationUrl()).then(function (content) {
       self._configuration = new Configuration(JSON.parse(content));
       return Promise.resolve(self._configuration);
     });
@@ -678,18 +646,35 @@ ServerConnector.getConfigurationParam = function (paramId) {
   }
   var self = this;
   return self.getConfiguration().then(function (configuration) {
-    return configuration.getOption(paramId);
+    var option = configuration.getOption(paramId);
+    if (option.getValue !== undefined) {
+      return option.getValue();
+    } else {
+      return option;
+    }
   });
 };
+ServerConnector.updateConfigurationOption = function (option) {
+  var self = this;
+  var queryParams = {
+    type: option.getType()
+  };
+  var filterParams = {
+    option: {
+      type: option.getType(),
+      value: option.getValue()
+    }
+  };
+  return self.sendPatchRequest(self.getConfigurationOptionUrl(queryParams), filterParams);
+};
 
 ServerConnector.getModels = function (projectId) {
   var queryParams = {};
   var filterParams = {};
-  var project;
   var self = this;
   return self.getProjectId(projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getModelsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getModelsUrl(queryParams, filterParams));
   }).then(function (content) {
     var models = [];
     var parsedJson = JSON.parse(content);
@@ -699,30 +684,34 @@ ServerConnector.getModels = function (projectId) {
     return models;
   });
 };
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-ServerConnector.getProject = function (projectId) {
-=======
 
-ServerConnector.getProject = function(projectId) {
->>>>>>> list of available projects
+ServerConnector.getProject = function (projectId) {
   var queryParams = {};
   var filterParams = {};
   var project;
   var self = this;
   return self.getProjectId(projectId).then(function (result) {
+    projectId = result;
     queryParams.projectId = result;
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-    return self.readFile(self.getProjectsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getProjectUrl(queryParams, filterParams));
   }).then(function (content) {
-=======
-    return self.readFile(self.getProjectUrl(queryParams, filterParams));
-  }).then(function(content) {
->>>>>>> list of available projects
-    project = new Project(content);
+    var downloadedProject = new Project(content);
+    if (self._projectsById[projectId] !== undefined) {
+      self._projectsById[projectId].update(downloadedProject);
+    } else {
+      self._projectsById[projectId] = downloadedProject;
+    }
+    project = self._projectsById[projectId];
     return self.getModels(projectId);
   }).then(function (models) {
     project.setModel(models[0]);
-    return self.getOverlays(projectId);
+    return self.getLoggedUser();
+  }).then(function (user) {
+    return self.getOverlays({
+      projectId: projectId,
+      creator: user.getLogin(),
+      publicOverlay: false,
+    });
   }).then(function (overlays) {
     project.getModel().addLayouts(overlays);
     return project;
@@ -742,34 +731,133 @@ ServerConnector.getProject = function(projectId) {
   });
 };
 
-<<<<<<< 9ae57951d8f3069d115122223234b4aac60c546f
-ServerConnector.getProjectStatistics = function (projectId) {
-=======
-ServerConnector.getProjects = function() {
+ServerConnector.updateProject = function (project) {
+  var self = this;
+  var queryParams = {
+    projectId: project.getProjectId()
+  };
+  var filterParams = {
+    project: {
+      name: project.getName(),
+      version: project.getVersion(),
+      notifyEmail: project.getNotifyEmail(),
+      organism: self.serialize(project.getOrganism()),
+      disease: self.serialize(project.getDisease()),
+    },
+  };
+  return self.sendPatchRequest(self.getProjectUrl(queryParams), filterParams).then(function (content) {
+    var downloadedProject = new Project(content);
+    project.update(downloadedProject);
+    return project;
+  }).then(null, function (error) {
+    if ((error instanceof NetworkError)) {
+      switch (error.statusCode) {
+        case HttpStatus.FORBIDDEN:
+          return Promise.reject(new SecurityError("Access denied."));
+        default:
+          return Promise.reject(error);
+      }
+    } else {
+      return Promise.reject(error);
+    }
+  });
+};
+
+ServerConnector.removeProject = function (projectId) {
+  var self = this;
+  var queryParams = {
+    projectId: projectId
+  };
+  return self.sendDeleteRequest(self.getProjectUrl(queryParams)).then(function (content) {
+    var project = new Project(content);
+    if (self._projectsById[project.getProjectId()] !== undefined) {
+      self._projectsById[project.getProjectId()].update(project);
+    } else {
+      self._projectsById[project.getProjectId()] = project;
+    }
+    return self._projectsById[project.getProjectId()];
+  }).then(null, function (error) {
+    if ((error instanceof NetworkError)) {
+      switch (error.statusCode) {
+        case HttpStatus.FORBIDDEN:
+          return Promise.reject(new SecurityError("Access denied."));
+        default:
+          return Promise.reject(error);
+      }
+    } else {
+      return Promise.reject(error);
+    }
+  });
+};
+
+ServerConnector.addProject = function (options) {
   var self = this;
-  if (self._projects !== undefined) {
+  var queryParams = {
+    projectId: options.projectId
+  };
+  return self.sendPostRequest(self.getProjectUrl(queryParams), options).then(function (content) {
+    var project = new Project(content);
+    if (self._projectsById[project.getProjectId()] !== undefined) {
+      self._projectsById[project.getProjectId()].update(project);
+    } else {
+      self._projectsById[project.getProjectId()] = project;
+    }
+    return project;
+  }).then(null, function (error) {
+    if ((error instanceof NetworkError)) {
+      switch (error.statusCode) {
+        case HttpStatus.FORBIDDEN:
+          return Promise.reject(new SecurityError("Access denied."));
+        default:
+          return Promise.reject(error);
+      }
+    } else {
+      return Promise.reject(error);
+    }
+  });
+};
+
+ServerConnector.serialize = function (object) {
+  var result = {};
+  if (object instanceof Annotation) {
+    result.type = object.getType();
+    result.resource = object.getResource();
+  } else {
+    throw new Error("Unhandled object type: " + (typeof object));
+  }
+  return result;
+};
+
+ServerConnector.getProjects = function (reload) {
+  var self = this;
+  if (self._projects.length > 0 && !reload) {
     return Promise.resolve(self._projects);
   } else {
-    return self.readFile(self.getProjectsUrl()).then(function(content) {
+    return self.sendGetRequest(self.getProjectsUrl()).then(function (content) {
       var parsedData = JSON.parse(content);
-      self._projects = [];
+      self._projects.length = 0;
       for (var i = 0; i < parsedData.length; i++) {
-        self._projects.push(new Project(JSON.stringify(parsedData[i])));
+        var project = new Project(JSON.stringify(parsedData[i]));
+        if (self._projectsById[project.getProjectId()] !== undefined) {
+          self._projectsById[project.getProjectId()].update(project);
+        } else {
+          self._projectsById[project.getProjectId()] = project;
+        }
+        self._projects.push(self._projectsById[project.getProjectId()]);
       }
       return self._projects;
     });
   }
 };
 
-ServerConnector.getProjectStatistics = function(projectId) {
->>>>>>> list of available projects
+ServerConnector.getProjectStatistics = function (projectId) {
   var queryParams = {};
   var filterParams = {};
   var self = this;
   var content;
   return self.getProjectId(projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getProjectStatisticsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getProjectStatisticsUrl(queryParams, filterParams));
   }).then(function (result) {
     content = JSON.parse(result);
     return self.getConfiguration();
@@ -793,24 +881,169 @@ ServerConnector.getLoggedUser = function () {
 ServerConnector.getUser = function (login) {
   var self = this;
   var queryParams = {
-    login: login,
+    login: login
   };
   var filterParams = {};
 
-  return self.readFile(self.getUserUrl(queryParams, filterParams)).then(function (content) {
+  return self.sendGetRequest(self.getUserUrl(queryParams, filterParams)).then(function (content) {
+    var obj = JSON.parse(content);
+    var user = new User(obj);
+    if (self._usersByLogin[user.getLogin()] !== undefined) {
+      self._usersByLogin[user.getLogin()].update(user);
+    } else {
+      self._usersByLogin[user.getLogin()] = user;
+    }
+    return self._usersByLogin[user.getLogin()];
+  }).then(null, function (error) {
+    return self.processNetworkError(error);
+  });
+};
+
+ServerConnector.updateUser = function (user) {
+  var self = this;
+  var queryParams = {
+    login: user.getLogin()
+  };
+  var filterParams = {
+    user: {
+      name: user.getName(),
+      surname: user.getSurname(),
+      password: user.getPassword(),
+      email: user.getEmail()
+    }
+  };
+  return self.sendPatchRequest(self.getUserUrl(queryParams), filterParams).then(function () {
+    return self.getConfiguration();
+  }).then(function (configuration) {
+    return self.updateUserPrivileges({user: user, privileges: user.privilegesToExport(configuration)});
+  });
+
+};
+ServerConnector.addUser = function (user) {
+  var self = this;
+  var queryParams = {
+    login: user.getLogin()
+  };
+  var filterParams = {
+    login: user.getLogin(),
+    name: user.getName(),
+    surname: user.getSurname(),
+    password: user.getPassword(),
+    email: user.getEmail()
+  };
+  return self.sendPostRequest(self.getUserUrl(queryParams), filterParams).then(function () {
+    return self.getConfiguration();
+  }).then(function (configuration) {
+    return self.updateUserPrivileges({user: user, privileges: user.privilegesToExport(configuration)});
+  });
+
+};
+
+ServerConnector.removeUser = function (login) {
+  var self = this;
+  var queryParams = {
+    login: login
+  };
+  return self.sendDeleteRequest(self.getUserUrl(queryParams));
+
+};
+
+ServerConnector.updateUserPrivileges = function (params) {
+  var self = this;
+  var queryParams = {
+    login: params.user.getLogin()
+  };
+
+  return self.sendPatchRequest(self.getUpdateUserPrivilegesUrl(queryParams), {
+    privileges: params.privileges
+  }).then(function (content) {
+    var obj = JSON.parse(content);
+    var user = new User(obj);
+    if (self._usersByLogin[user.getLogin()] !== undefined) {
+      self._usersByLogin[user.getLogin()].update(user);
+    } else {
+      self._usersByLogin[user.getLogin()] = user;
+    }
+    return self._usersByLogin[user.getLogin()];
+  }).then(null, function (error) {
+    return self.processNetworkError(error);
+  });
+};
+
+ServerConnector.processNetworkError = function (error) {
+  if ((error instanceof NetworkError)) {
+    switch (error.statusCode) {
+      case HttpStatus.NOT_FOUND:
+        return null;
+      case HttpStatus.FORBIDDEN:
+        return Promise.reject(new SecurityError("Access denied."));
+      default:
+        return Promise.reject(error);
+    }
+  } else {
+    return Promise.reject(error);
+  }
+};
+
+
+ServerConnector.updateUserPreferences = function (params) {
+  var self = this;
+  var queryParams = {
+    login: params.user.getLogin()
+  };
+
+  return self.sendPatchRequest(self.getUpdateUserPreferencesUrl(queryParams), {
+    preferences: params.preferences.toExport()
+  }).then(function (content) {
     var obj = JSON.parse(content);
-    return new User(obj);
+    var user = new User(obj);
+    if (self._usersByLogin[user.getLogin()] !== undefined) {
+      self._usersByLogin[user.getLogin()].update(user);
+    } else {
+      self._usersByLogin[user.getLogin()] = user;
+    }
+    return self._usersByLogin[user.getLogin()];
   });
 };
 
-ServerConnector.getOverlays = function (projectId) {
+ServerConnector.getUsers = function (forceRefresh) {
   var self = this;
+
+  if (self._users.length > 0 && !forceRefresh) {
+    return Promise.resolve(self._users);
+  } else {
+    return self.sendGetRequest(self.getUsersUrl()).then(function (content) {
+      var parsedData = JSON.parse(content);
+      self._users.length = 0;
+      for (var i = 0; i < parsedData.length; i++) {
+        var user = new User(parsedData[i]);
+        if (self._usersByLogin[user.getLogin()] !== undefined) {
+          self._usersByLogin[user.getLogin()].update(user);
+        } else {
+          self._usersByLogin[user.getLogin()] = user;
+        }
+        self._users.push(self._usersByLogin[user.getLogin()]);
+      }
+      return self._users;
+    });
+  }
+
+};
+
+ServerConnector.getOverlays = function (params) {
+  var self = this;
+  if (params === undefined) {
+    params = {};
+  }
   var queryParams = {};
-  var filterParams = {};
+  var filterParams = {
+    creator: params.creator,
+    publicOverlay: params.publicOverlay,
+  };
   return new Promise(function (resolve, reject) {
-    self.getProjectId(projectId).then(function (result) {
+    self.getProjectId(params.projectId).then(function (result) {
       queryParams.projectId = result;
-      return self.readFile(self.getOverlaysUrl(queryParams, filterParams));
+      return self.sendGetRequest(self.getOverlaysUrl(queryParams, filterParams));
     }).then(function (content) {
       var arr = JSON.parse(content);
       var result = [];
@@ -835,7 +1068,7 @@ ServerConnector.getOverlayElements = function (overlayId, projectId) {
   var filterParams = {};
   return self.getProjectId(projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getOverlayElementsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getOverlayElementsUrl(queryParams, filterParams));
   }).then(function (content) {
     var arr = JSON.parse(content);
     var result = [];
@@ -865,7 +1098,7 @@ ServerConnector.getFullOverlayElement = function (params) {
 
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getFullOverlayElementUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getFullOverlayElementUrl(queryParams, filterParams));
   }).then(function (content) {
     var element = JSON.parse(content);
     var result = null;
@@ -911,13 +1144,13 @@ ServerConnector.getOverlayById = function (overlayId, projectId) {
   var filterParams = {};
   return self.getProjectId(projectId).then(function (data) {
     queryParams.projectId = data;
-    return self.readFile(self.getOverlayByIdUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getOverlayByIdUrl(queryParams, filterParams));
   }).then(function (content) {
     return new LayoutData(JSON.parse(content));
   });
 };
 
-ServerConnector.getReactions = function(params) {
+ServerConnector.getReactions = function (params) {
   var self = this;
   var queryParams = {};
   if (params.ids === undefined) {
@@ -936,10 +1169,10 @@ ServerConnector.getReactions = function(params) {
     if (filterParams.id.length > 100 || filterParams.participantId.length > 100) {
       return self.sendPostRequest(self.getReactionsUrl(queryParams), filterParams);
     } else {
-      return self.readFile(self.getReactionsUrl(queryParams, filterParams));
+      return self.sendGetRequest(self.getReactionsUrl(queryParams, filterParams));
     }
 
-  }).then(function(content) {
+  }).then(function (content) {
     var array = JSON.parse(content);
     var result = [];
     for (var i = 0; i < array.length; i++) {
@@ -952,7 +1185,7 @@ ServerConnector.getReactions = function(params) {
 ServerConnector.getAliases = function (params) {
   var self = this;
   var queryParams = {
-    modelId: params.modelId,
+    modelId: params.modelId
   };
   if (params.ids === undefined) {
     params.ids = [];
@@ -964,11 +1197,11 @@ ServerConnector.getAliases = function (params) {
     params.excludedCompartmentIds = [];
   }
   var filterParams = {
-    id : params.ids,
-    columns : params.columns,
-    type : params.type,
-    excludedCompartmentIds : params.excludedCompartmentIds,
-    includedCompartmentIds : params.includedCompartmentIds,
+    id: params.ids,
+    columns: params.columns,
+    type: params.type,
+    excludedCompartmentIds: params.excludedCompartmentIds,
+    includedCompartmentIds: params.includedCompartmentIds
 
   };
   return self.getProjectId(params.projectId).then(function (result) {
@@ -976,7 +1209,7 @@ ServerConnector.getAliases = function (params) {
     if (filterParams.id.length > 100) {
       return self.sendPostRequest(self.getAliasesUrl(queryParams), filterParams);
     } else {
-      return self.readFile(self.getAliasesUrl(queryParams, filterParams));
+      return self.sendGetRequest(self.getAliasesUrl(queryParams, filterParams));
     }
   }).then(function (content) {
     var array = JSON.parse(content);
@@ -1005,7 +1238,7 @@ ServerConnector.getComments = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getCommentsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getCommentsUrl(queryParams, filterParams));
   }).then(function (content) {
     var array = JSON.parse(content);
     var result = [];
@@ -1037,7 +1270,7 @@ ServerConnector.getClosestElementsByCoordinates = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchUrl(queryParams, filterParams));
   }).then(function (content) {
     var array = JSON.parse(content);
     var result = [];
@@ -1074,7 +1307,7 @@ ServerConnector.logout = function () {
   var self = this;
   self.getSessionData().setToken(undefined);
   self.getSessionData().setLogin(undefined);
-  return self.readFile(self.logoutUrl());
+  return self.sendGetRequest(self.logoutUrl());
 };
 
 ServerConnector.getElementsByQuery = function (params) {
@@ -1089,7 +1322,7 @@ ServerConnector.getElementsByQuery = function (params) {
 
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchUrl(queryParams, filterParams));
   }).then(function (content) {
     var array = JSON.parse(content);
     var result = [];
@@ -1108,7 +1341,7 @@ ServerConnector.getDrugsByQuery = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchDrugsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchDrugsUrl(queryParams, filterParams));
   }).then(function (content) {
     var array = JSON.parse(content);
     var result = [];
@@ -1127,7 +1360,7 @@ ServerConnector.getMiRnasByQuery = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchMiRnasUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchMiRnasUrl(queryParams, filterParams));
   }).then(function (content) {
     var array = JSON.parse(content);
     var result = [];
@@ -1146,7 +1379,7 @@ ServerConnector.getChemicalsByQuery = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchChemicalsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchChemicalsUrl(queryParams, filterParams));
   }).then(function (content) {
     var array = JSON.parse(content);
     var result = [];
@@ -1245,7 +1478,7 @@ ServerConnector.getDrugNamesByTarget = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchDrugsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchDrugsUrl(queryParams, filterParams));
   }).then(function (content) {
     var result = [];
     var object = JSON.parse(content);
@@ -1265,7 +1498,7 @@ ServerConnector.getMiRnaNamesByTarget = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchMiRnasUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchMiRnasUrl(queryParams, filterParams));
   }).then(function (content) {
     var result = [];
     var object = JSON.parse(content);
@@ -1285,7 +1518,7 @@ ServerConnector.getChemicalNamesByTarget = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getSearchChemicalsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getSearchChemicalsUrl(queryParams, filterParams));
   }).then(function (content) {
     var result = [];
     var object = JSON.parse(content);
@@ -1302,7 +1535,7 @@ ServerConnector.addComment = function (params) {
     elementId: params.elementId,
     elementType: params.elementType,
     coordinates: self.pointToString(params.coordinates),
-    modelId: params.modelId,
+    modelId: params.modelId
   };
   var filterParams = params;
   delete filterParams.elementId;
@@ -1323,34 +1556,40 @@ ServerConnector.addComment = function (params) {
 };
 
 ServerConnector.addOverlay = function (params) {
+  var overlay = params.overlay;
+  if (!(overlay instanceof LayoutData)) {
+    throw new Error("Invalid overlay: " + overlay);
+  }
   var self = this;
   var queryParams = {};
+  var data = {
+    name: overlay.getName(),
+    description: overlay.getDescription(),
+    content: overlay.getContent(),
+    filename: overlay.getFilename()
+  };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.sendPostRequest(self.addOverlayUrl(queryParams), params);
+    return self.sendPostRequest(self.addOverlayUrl(queryParams), data);
   }).then(function (content) {
     return new LayoutData(JSON.parse(content));
   });
 };
 
-ServerConnector.updateOverlay = function (params) {
+ServerConnector.updateOverlay = function (overlay) {
   var self = this;
   var queryParams = {
-    overlayId: params.overlayId
+    overlayId: overlay.getId()
   };
   var filterParams = {
-    overlay: {}
+    overlay: {
+      name: overlay.getName(),
+      description: overlay.getDescription(),
+      creator: overlay.getCreator(),
+      publicOverlay: overlay.getPublicOverlay()
+    }
   };
-  if (params.name !== undefined) {
-    filterParams.overlay.name = params.name;
-  }
-  if (params.description !== undefined) {
-    filterParams.overlay.description = params.description;
-  }
-  return self.getProjectId(params.projectId).then(function (result) {
-    queryParams.projectId = result;
-    return self.sendPatchRequest(self.updateOverlayUrl(queryParams), filterParams);
-  });
+  return self.sendPatchRequest(self.updateOverlayUrl(queryParams), filterParams);
 };
 
 ServerConnector.removeOverlay = function (params) {
@@ -1365,11 +1604,23 @@ ServerConnector.removeOverlay = function (params) {
   });
 };
 
+ServerConnector.removeComment = function (params) {
+  var self = this;
+  var queryParams = {
+    commentId: params.commentId
+  };
+  var filterParams = {};
+  return self.getProjectId(params.projectId).then(function (result) {
+    queryParams.projectId = result;
+    return self.sendDeleteRequest(self.deleteCommentUrl(queryParams), filterParams);
+  });
+};
+
 ServerConnector.getSuggestedQueryList = function (projectId) {
   var self = this;
   return self.getProjectId(projectId).then(function (result) {
     projectId = result;
-    return self.readFile(self.getSuggestedQueryListUrl({
+    return self.sendGetRequest(self.getSuggestedQueryListUrl({
       projectId: projectId
     }));
   }).then(function (content) {
@@ -1396,11 +1647,11 @@ ServerConnector.getPublications = function (params) {
     length: params.length,
     sortColumn: params.sortColumn,
     sortOrder: params.sortOrder,
-    search: params.search,
+    search: params.search
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    return self.readFile(self.getPublicationsUrl(queryParams, filterParams));
+    return self.sendGetRequest(self.getPublicationsUrl(queryParams, filterParams));
   }).then(function (content) {
     return JSON.parse(content);
   });
@@ -1409,9 +1660,39 @@ ServerConnector.getPublications = function (params) {
 ServerConnector.getReferenceGenome = function (params) {
   var self = this;
   var filterParams = {};
-  return self.readFile(self.getReferenceGenomeUrl(params, filterParams)).then(function (content) {
+  return self.sendGetRequest(self.getReferenceGenomeUrl(params, filterParams)).then(function (content) {
     return new ReferenceGenome(JSON.parse(content));
   });
 };
 
+ServerConnector.uploadFile = function (params) {
+  var CHUNK_SIZE = 65535;
+  var self = this;
+  var data = new Uint8Array(params.content);
+  var filterParams = {
+    filename: params.filename,
+    length: data.length
+  };
+
+  return self.sendPostRequest(self.getCreateFileUrl(), filterParams).then(function (response) {
+    var uploadedLength = 0;
+    var createPromise = function (resultFileJson) {
+      var resultFile = JSON.parse(resultFileJson);
+      if (uploadedLength >= data.length) {
+        return Promise.resolve(resultFile);
+      } else {
+        var chunk = data.slice(uploadedLength, uploadedLength + CHUNK_SIZE);
+        logger.debug("SEND " + chunk.length + " bytes");
+        var url = self.getUploadFileUrl({id: resultFile.id});
+        return self.sendRequest({method: "POST", url: url, body: chunk}).then(function (resultFileJson) {
+          uploadedLength += chunk.length;
+          logger.debug("RESPONSE ", resultFileJson);
+          return createPromise(resultFileJson);
+        })
+      }
+    };
+    return createPromise(response);
+  });
+};
+
 module.exports = ServerConnector;