diff --git a/.aspell-api-exceptions.pws b/.aspell-api-exceptions.pws
new file mode 100644
index 0000000000000000000000000000000000000000..2f5c04dda5012ffb8eea710c86fc5a2bf661a38e
--- /dev/null
+++ b/.aspell-api-exceptions.pws
@@ -0,0 +1,703 @@
+personal_ws-1.1 en 0 utf-8
+acetylated
+aceview
+adw
+affy
+aftol
+Agitans
+al
+aliasId
+allergome
+amoebadb
+analyte
+Analytics
+annotatorClass
+annotatorClassName
+antibodyregistry
+antweb
+apd
+aphidbase
+april
+arachnoserver
+ardb
+arrayexpress
+arxiv
+aspgd
+assoiated
+atc
+atcc
+atcvet
+atfdb
+autdb
+avogadro
+backgroundId
+backgroundOverlayId
+bacmap
+bdgp
+beetlebase
+bgee
+bieEntity
+bigg
+bindingDB
+biocarta
+biocatalogue
+biocyc
+bioEntites
+bioEntity
+Bioentity
+bioEntityFields
+biogrid
+Biomedicine
+biomodels
+BioModels
+BIOMODELS
+bionumbers
+bioportal
+bioproject
+biosample
+biosystems
+bitterdb
+bloodBrainBarrier
+Bname
+boundaryCondition
+boxSize
+brainstem
+brandNames
+brenda
+briefView
+Broot
+bto
+Btype
+bugbase
+buildDate
+bvar
+bykdb
+candela
+cas
+CAS
+cath
+cattleqtldb
+cazy
+ccd
+CCD
+ccds
+CCDS
+cco
+cdd
+CDMT
+cdpd
+cef
+cellimage
+CENRAL
+centerPoint
+cgd
+cgsc
+charprot
+chebi
+Chebi
+ChEMBL
+chemdb
+chemidplus
+chemspider
+ChemSpider
+CHEMSPIDER
+chickenqtldb
+ci
+citationCount
+className
+cldb
+clinicaltrials
+clinvar
+clo
+coeruleus
+commentId
+commonName
+compartmentId
+complexId
+compulyeast
+connectedToLdap
+conoserver
+coord
+coriell
+corum
+coulumb
+cpc
+CPC
+creationDate
+cryptodb
+csa
+cst
+ctd
+cubedb
+cutdb
+dailymed
+darc
+datatable
+datetime
+datf
+dbd
+dbest
+dbg
+dbprobe
+dbsnp
+defaultOverlay
+defaultPrivileges
+degradome
+depod
+desc
+dictybase
+disprot
+dmet
+DN
+dna
+doi
+doid
+dommino
+DONT
+doqcs
+downloadImage
+downloadModel
+downloadProgress
+downloadSource
+dpv
+dragondb
+drsc
+drugbank
+drugbankv
+ebimetagenomics
+ec
+echobase
+eco
+ecogene
+ecoliwiki
+edam
+efo
+ega
+elementAnnotations
+elementClassNames
+elementId
+elementIds
+elementTypes
+embl
+ena
+ensembl
+entrez
+environ
+epd
+et
+euclinicaltrials
+exac
+excludedCompartmentIds
+expt
+fb
+ffccffcc
+fff
+FFFFFF
+fileId
+filteredSize
+flybase
+fma
+Fmapping
+foodb
+formerSymbols
+Fs
+fsnp
+fullName
+funcbase
+functionId
+functionIds
+fungidb
+gabi
+gcms
+genatlas
+genecards
+genedb
+genefarm
+geneMapping
+genetree
+geneVariations
+genewiki
+genomeId
+genomeType
+genomeTypes
+genomeVersion
+genpept
+genprop
+geo
+getAvailableRemoteUrls
+giardiadb
+gitHash
+glida
+glycan
+glycoepitope
+glycomedb
+glycosylated
+gmd
+goa
+googleLicenseConsent
+gpcr
+gpcrdb
+gpml
+gramene
+grantPrivileges
+greengenes
+grp
+grsdb
+gsta
+gui
+gwascentral
+gxa
+hamap
+handlerClass
+hcvdb
+hdr
+henry
+hg
+hgmd
+hgnc
+hierarchyVisibilityLevel
+hinv
+HIPAA
+hla
+hmdb
+HMDB
+hogenom
+homd
+homologene
+hovergen
+hpa
+hpm
+hprd
+href
+hs
+hssp
+hydroxylated
+icd
+idObject
+idot
+ie
+imageFormats
+imageLinkId
+IMAP
+imex
+img
+IMG
+imgt
+inchi
+InChi
+inchikey
+initialAmount
+initialConcentration
+innerPosition
+inputFormat
+inputType
+insdc
+interpro
+InterPro
+INTERPRO
+introns
+ird
+irefweb
+isbn
+isDefault
+isfinder
+isoform
+Isoform
+ISOFORM
+isPublic
+isServerSide
+issn
+iuphar
+jaxmice
+jcggdb
+jcm
+jcsd
+jstor
+june
+jws
+katal
+kegg
+kineticLaw
+kineticrecord
+kisao
+KnapSack
+lastActive
+lcsb
+ldapAccountAvailable
+lepra
+Lewy
+LEWY
+lgic
+ligandbox
+ligandexpo
+ligm
+lincs
+linkedSubmodel
+lipidbank
+lipidmaps
+listOfAntisenseRNAs
+listOfBlockDiagrams
+listOfCompartmentAliases
+listOfCompartments
+listOfComplexSpeciesAliases
+listOfGenes
+listOfGroups
+listOfLayers
+listOfProteins
+listOfRNAs
+listOfSpecies
+listOfSpeciesAliases
+listOfUnitDefinitions
+listOfUnits
+localUrl
+logEntries
+lrg
+lsid
+macie
+maizegdb
+mamo
+mapCanvasType
+mapCanvasTypes
+mapName
+mappingName
+mapTypes
+masklike
+massbank
+mathMl
+mathMlPresentation
+matrixdb
+maxColor
+maxZoom
+MCS
+medlineplus
+merops
+MeSH
+meshId
+metabolights
+metagenome
+metaid
+metazoa
+methylated
+metlin
+mgd
+MGD
+MGnify
+MGNIFY
+microsporidia
+mimodb
+minColor
+MINERVANET
+minZoom
+mipmod
+mirbase
+miRBase
+mirex
+MiriamType
+miriamTypes
+miRnas
+mirnest
+miRTarBase
+mmdb
+mmrrc
+modeldb
+modelDisplay
+modelFormats
+modelId
+modelLinkId
+modelPoint
+modelVersion
+modificationDates
+modificationStateTypes
+molbase
+mpid
+mrow
+myco
+mycobank
+myristoylated
+namebank
+napp
+narcis
+nasc
+nbn
+nbrc
+ncbi
+ncbigene
+ncbiprotein
+ncim
+ncit
+ndc
+neurolex
+neurologic
+neuromorpho
+neurondb
+neutralColor
+nextdb
+nextprot
+nI
+niaest
+nigra
+nKind
+noncode
+noncodev
+norine
+notifyEmail
+NPJ
+nuclearbd
+oai
+objectClass
+objectId
+objectIdentifier
+objectType
+obo
+Ok
+oma
+omia
+omim
+OMIM
+opb
+opm
+orcid
+ordb
+ordo
+organismId
+oridb
+orphanet
+orthodb
+Orthologous
+orthology
+Orthology
+ORTHOLOGY
+oryzabase
+otl
+outputFormat
+overlayContent
+overlayId
+overlayIds
+overlayTypes
+OverviewImage
+OverviewImageLink
+overviewImageViews
+OverviewModelLink
+OverviewSearchLink
+paleodb
+palmytoylated
+parameterId
+parameterIds
+parentClass
+parkinsonism
+participantId
+Pathologic
+pathwaycommons
+pato
+paxdb
+pazar
+pdb
+PDB
+peptideatlas
+perfectMatch
+peroxibase
+pfam
+PFAM
+PHARM
+pharmgkb
+phenolexplorer
+phosphopoint
+phosphorylated
+PHOSPHORYLATED
+phosphosite
+phylomedb
+phytozome
+pid
+pigqtldb
+pina
+piroplasma
+pirsf
+plasmodb
+pmap
+pmc
+pmdb
+po
+pocketome
+polbase
+polygonString
+pombase
+positionToCompartment
+postive
+prenylated
+privilegeType
+privilegeTypes
+probeset
+prodom
+proglyc
+proj
+projectBackground
+prosite
+protclustdb
+proteincard
+proteinReference
+proteomicsdb
+protist
+protonated
+protonet
+pscdb
+pseudomonas
+psimi
+psimod
+psipar
+pthcmp
+pubchem
+publicOverlay
+PubMed
+pubmedId
+pw
+qtl
+reactionAnnotations
+reactionIds
+reactionTypes
+rebase
+refseq
+RefSeq
+REFSEQ
+registryIdentifier
+removeReason
+requestResetPassword
+resid
+retropulsion
+revokePrivileges
+rfam
+rgd
+ricegap
+rna
+rnai
+rnamods
+ro
+sa
+sabiork
+sacch
+samp
+sbgn
+sbo
+scop
+scretf
+sdbs
+sgd
+SGD
+sgn
+sharedInMinervaNet
+sheepqtldb
+sider
+siemens
+sievert
+simpleColor
+singleLine
+sitex
+sizeX
+sizeY
+smeg
+smpdb
+snomedct
+sortColumn
+sortOrder
+sourceUrl
+soybase
+speciesAlias
+speciesIdentity
+sra
+stap
+steradian
+structuralState
+submapConnections
+substantia
+substratedb
+subtilist
+subtiwiki
+suggestedQueryList
+sulfated
+supfam
+swiss
+tair
+tarbase
+targetElements
+targetParticipants
+taxonomyId
+tcdb
+termsOfUseConsent
+tesla
+tgd
+th
+tigrfam
+tileSize
+tissuelist
+tol
+topdb
+topfind
+topOverviewImage
+totalSize
+Toxicogenomic
+TOXICOGENOMIC
+toxoplasma
+transparencyLevel
+treebase
+treefam
+trichdb
+tritrypdb
+ttd
+Ub
+uberon
+ubio
+ubiquitinated
+udl
+umbbd
+unigene
+UniGene
+UNIGENE
+unii
+unimod
+uniparc
+uniprot
+Uniprot
+uniqueId
+unists
+unitDefinition
+unitId
+unitsId
+unitTypeFactors
+unitTypes
+updatePreferences
+updatePrivileges
+uploadedDataLength
+uris
+uspto
+usualView
+validConnection
+valueType
+vario
+vbase
+vbrc
+vfdb
+viralzone
+virsirna
+vmhmetabolite
+vmhreaction
+weber
+wikidata
+Wikidata
+WIKIDATA
+wikigenes
+wikipathways
+WikiPathways
+WIKIPATHWAYS
+wikipedia
+worfdb
+wormbase
+wormpep
+xenbase
+xhtml
+xmlns
+xxxxxxxx
+ydpm
+yeastintron
+yetfasco
+yrcpdr
+zfin
+zoomLevel
diff --git a/.aspell.en.pws b/.aspell.en.pws
new file mode 100644
index 0000000000000000000000000000000000000000..d55156159364099eba8cb9d180d7bd8b5a01dd1c
--- /dev/null
+++ b/.aspell.en.pws
@@ -0,0 +1,568 @@
+personal_ws-1.1 en 0 utf-8
+Acetosalic
+ACETYLOXY
+ACETYLSALIC
+Acetylsalicylic
+ACETYLSALICYLIC
+ACETYLSALICYLICUM
+Aceview
+ACIDUM
+actomyosin
+Affymetrix
+AFTOL
+ALKA
+allel
+Allergome
+AmoebaDB
+ANADIN
+Analyte
+ANGETTES
+antisense
+AntWeb
+APD
+AphidBase
+api
+Arabidopsis
+ArachnoServer
+ARITOX
+ArrayExpress
+arXiv
+asc
+AspGD
+ASPRO
+ATCC
+ATH
+AutDB
+AUTH
+autocomplete
+autofill
+BackgroundColor
+BacMap
+BBD
+bcrypt
+BDGP
+BeetleBase
+BENZOIC
+BEVASIRANIB
+Bgee
+BiGG
+BindingDB
+bioassay
+BioCarta
+BioCatalogue
+BioCompendium
+BioCyc
+bioEntities
+BioEntity
+BioGRID
+BioNumbers
+biopax
+BioPortal
+BioProject
+BioSample
+BioSystems
+Biotransformation
+BitterDB
+BOM
+boolean
+BorderColor
+bqbiol
+bqmodel
+BugBase
+BYKdb
+capslock
+cardinality
+CATH
+CAZy
+celldesigner
+CellDesigner
+CGSC
+CharProt
+charset
+CHEBI
+checkboxes
+chembl
+ChemDB
+ChemIDplus
+Chuderland
+CLDB
+ClinicalTrials
+ClinVar
+CLR
+compartmentRef
+Compulyeast
+Concurent
+config
+Conoserver
+contect
+contentType
+coords
+COPASI
+Coriell
+CORS
+CORUM
+cron
+CryptoDB
+CSA
+css
+CTD
+ctdbase
+curation
+CutDB
+CVE
+cyclooxygenase
+DailyMed
+DANAMEP
+DAPI
+DARC
+DataBase
+dataset
+datasets
+DATF
+dbconfig
+DBD
+dbEST
+DBG
+dbProbe
+dbSNP
+debian
+defaultCenterX
+defaultCenterY
+defaultZoomLevel
+Degradome
+Denda
+DEPOD
+dialogs
+Dictybase
+DISPRIN
+DisProt
+DMET
+DOI
+DOMMINO
+DORLIMOMAB
+DPV
+DragonDB
+DRSC
+DrugBank
+ds
+DURLAZA
+eboVir
+EchoBASE
+EcoGene
+EcoliWiki
+Ecotrin
+eggNOG
+elementIdentifier
+ENA
+ENPRIN
+Ensembl
+Entrez
+enviPath
+Environ
+EPD
+Equi
+ExAC
+Expt
+Feng
+FlyBase
+FMA
+FooDB
+frontend
+FuncBase
+FungiDB
+Fyn
+GABI
+Gawron
+GC
+Gebel
+Genatlas
+GENCARDIA
+GeneCards
+GeneDB
+GeneFarm
+geneMappingId
+GeneTree
+genomeId
+genomic
+GenPept
+getWriter
+GiardiaDB
+GLIDA
+Glycan
+Glycoconjugate
+GlycoEpitope
+GlycomeDB
+glyphs
+glypican
+Golm
+GPC
+GPCR
+GPCRDB
+GPML
+Gramene
+graphicalObject
+GreenGenes
+Grossman
+GRSDB
+GWAS
+GXA
+HAMAP
+Harada
+hasInstance
+hasProperty
+hasTaxon
+Hatanaka
+HCVDB
+heterodimer
+HGMD
+HGNC
+Hikari
+Hiramoto
+HLA
+HOGENOM
+HOMD
+Homeodomain
+HomoloGene
+homomultimer
+HOVERGEN
+HPA
+HPRD
+hsa
+HSSP
+html
+http
+https
+hungs
+ICD
+ICEberg
+IMEx
+IMGT
+InChI
+InChIKey
+includedCompartmentIds
+InfoWindow
+IntAct
+Intron
+Introns
+InvDb
+IRD
+iRefWeb
+isDerivedFrom
+ISFinder
+isInstanceOf
+isPropertyOf
+ISSN
+IUPHAR
+javascript
+JAX
+JCGGDB
+Jiang
+jpg
+JS
+json
+JSTOR
+JWS
+KA
+Kawakubo
+Kawamura
+Kegg
+KEGG
+KiSAO
+KNApSAcK
+Kuzma
+LayerText
+layouted
+LDAP
+leprae
+LEVIUS
+ligand
+LigandBox
+LIGM
+LINCS
+lineWidth
+LipidBank
+logrotate
+lu
+Luo
+MACiE
+MaizeGDB
+mapId
+marinum
+MassBank
+MatrixDB
+Matsumoto
+Mazein
+md
+MEASURIN
+MedlinePlus
+MEROPS
+MetaboLights
+Metabolome
+Metagenome
+Metainformation
+MetaNetX
+Metazoa
+METLIN
+MGED
+MICROPIRIN
+microRNA
+MicrosporidiaDB
+MimoDB
+minerva
+MINERVA’s
+MIPModDB
+miR
+mirEX
+miriam
+miRNA
+miRNAs
+miRNEST
+mirtarbase
+misalign
+misaligning
+MMRRC
+ModelDB
+MolArt
+Molbase
+multimer
+multimers
+MycoBank
+MycoBrowser
+NADH
+Nakano
+NameBank
+namespace
+NAPP
+NARCIS
+NASC
+NCBI
+NCI
+NCIm
+NCIt
+NeuroLex
+NeuroMorpho
+NeuronDB
+NEXTDB
+nextProt
+NIAEST
+Ninio
+NITE
+NONCODE
+NORINE
+Noshiro
+NucleaRDB
+occursIn
+OMA
+OMIA
+openjdk
+OpenLayers
+OPM
+ORCID
+OriDB
+Orphanet
+OrthoDB
+Oryza
+Oryzabase
+Ostaszewski
+Otjacques
+overlayed
+PaleoDB
+parseable
+PATO
+PaxDb
+PAYNOCIL
+Pazar
+pdf
+pdmap
+PDR
+PeptideAtlas
+Peroxibase
+PharmGKB
+phenome
+phenotypes
+phentoype
+PhosphoPoint
+Phosphoprotein
+PhosphoSite
+PhylomeDB
+Phytozome
+PINA
+Piotr
+PiroplasmaDB
+PIRSF
+PlasmoDB
+PLATET
+PMC
+pmceurope
+PMP
+png
+Pocketome
+PolBase
+PomBase
+postgres
+postgresql
+POSTMI
+posttranslational
+PredictProtein
+Prin
+Probeset
+ProDom
+ProGlycProt
+projectId
+PROSITE
+ProtClustDB
+ProteinCard
+Proteome
+ProteomicsDB
+Protists
+ProtoNet
+PSCDB
+Pseudomonas
+PTGS
+PubChem
+pubmed
+px
+Qiu
+qTL
+QTL
+QuickStart
+RDF
+reactionId
+reactionIdentifier
+reactome
+REBASE
+removeAllListeners
+reportable
+repositioned
+RESID
+resizeable
+reupload
+revalidated
+reverseReaction
+RFAM
+RGD
+RhoA
+RHOA
+RK
+RNAi
+RNAs
+RoundedRectangle
+Ruan
+SABIO
+Saccharomyces
+SALICYLATE
+Salicylic
+Satagopam
+Sato
+SBGN
+SBGNML
+sbml
+SBML
+SBO
+ScerTF
+Schizosaccharomyces
+SCOP
+scrollbar
+scrollbars
+SearchListener
+selectable
+SemanticZoomLevelTransparency
+Shalgi
+ShapeType
+Shomron
+SIDER
+SitEx
+smegmatis
+SMTP
+SNOMED
+SNP
+sortable
+SoyBase
+speciesReference
+specific
+SSL
+STAP
+stoichiometry
+STRGH
+subfolders
+submap
+submaps
+submodel
+submodels
+substanceUnits
+SubstrateDB
+SubtiList
+SubtiWiki
+superfamily
+SUPFAM
+svg
+SwissLipids
+symlink
+Tair
+TAIR
+TarBase
+targetting
+Taxnomy
+Tetrahymena
+TFDB
+Thaliana
+TIGRFAMS
+timeouted
+TOPDB
+TopFind
+ToS
+ToxoDB
+TransparencyZoomLevelVisibility
+TreeBASE
+TreeFam
+TrichDB
+TriTrypDB
+TTD
+txt
+UBERON
+uBio
+ubuntu
+UCSC
+uid
+un
+unhandled
+unicode
+UNII
+Unimod
+UniParc
+UniPathway
+UniProt
+UniSTS
+uri
+url
+urlencoded
+urls
+USPTO
+UTF
+VariO
+VAZALORE
+Vbase
+VBRC
+Vetinary
+VFDB
+viewBox
+ViralZone
+VIRsiRNA
+vmh
+webpage
+whitespace
+WikiGenes
+Worfdb
+WormBase
+Wormpep
+www
+Xenbase
+xml
+xsd
+xss
+YDPM
+YeTFasCo
+YRC
+ZFIN
+Zhang
+Zorzan
diff --git a/.gitignore b/.gitignore
index 086453b02d6c62843ccb976bbeac9ebf476e8ff1..3193dd9a22fbecf20f4ef209c5a3739c68d03a2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ service/minerva-big/
 #eclipse files
 .classpath
 .settings
+.externalToolBuilders
 
 #maven build files
 target/
@@ -28,3 +29,6 @@ debian/src/*.sql
 
 #rpm build files
 rpm/rpmbuildtemp/
+
+#local test
+web/src/test/java/lcsb/mapviewer/web/TestXXX.java
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9cc9e8425e1690a6ca7b625230ebcc513ce1a7f6..2d6c98f81d2b348d7e8238bd651b45b144ab543f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -589,3 +589,11 @@ test_postgres_14_compatibility:
   <<: *test_database_definition
   services:
     - postgres:14
+
+changelog_spelling:
+   image: debian
+   stage: test
+   script:
+      - apt-get update
+      - apt-get install -y aspell aspell-en
+      - ./test_spelling.sh
diff --git a/CHANGELOG b/CHANGELOG
index 2c038263d1ed5a2c3c77cc77a7a0bb1004847d3c..0bc4cdd6dc60aa246c827d3616879d2e1b259cd0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -13,9 +13,91 @@ minerva (16.3.0) unstable; urgency=medium
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Mon, 27 Jun 2022 15:00:00 +0200
 
+minerva (16.2.10) stable; urgency=medium
+  * Bug fix (API documentation): typos in API documentation corrected (#1806)
+  * Bug fix (API documentation): header in logout method change to keep
+    consistency with other methods (#1806)
+  * Bug fix (API documentation): missing information about genomeId added when
+    adding gene mapping (#1807)
+  * Bug fix: exporting map with data overlay coloring did not work (#1817)
+  * Bug fix: non-numeric character in pubmed id prevent publications from
+    being downloaded (#1802)
+  * Bug fix: line width was ignored when fetching information about advanced
+    data overlay (#1742)
+  * Bug fix: global xml namespace definition caused MINERVA to fail on
+    processing model notes (#1804)
+  * Bug fix: genetic data overlays from zip input did not contain proper info
+    about genome (#1815)
+  * Bug fix: overlay genetic data that contained multiple matches (for example
+    two different uniprot ID for the same gene) caused problem when visualizing
+    genome browser (#1815)
+  * Bug fix: when exporting elements the list of selected excluded/included
+    compartments was too long then the error was raised (#1798)
+  * Bug fix: when merged results in left panel contained different submap link
+    minerva crashed (#1764)
+
+ -- Piotr Gawron <piotr.gawron@uni.lu>  Wed, 25 Jan 2023 12:00:00 +0200
+
+minerva (16.2.9) stable; urgency=medium
+  * Bug fix (API documentation): authentication token is not needed (and
+    misleading) when accessing list of projects from guest account (#1775)
+  * Bug fix (API documentation): missing authentication token in logout
+    sample (#1775)
+  * Bug fix (API documentation): when starting downloading genome data the
+    response fields is empty and unnecessary (#1775)
+  * Bug fix (API documentation): information where genomeId can be found
+    added (#1775)
+  * Bug fix (API documentation): information where geneMappingId can be
+    found added (#1775)
+  * Bug fix (API documentation): when creating user use better user password
+    example (#1775)
+  * Bug fix (API documentation): when creating user list of parameters was
+    wrong (#1775)
+  * Bug fix (API documentation): remove unnecessary "-i" option in curl
+    examples (#1775)
+  * Bug fix: parsing GPML file with unknown ShapeType caused errors during
+    parsing (#1776)
+  * Bug fix: information about layers was not merged in merge API call (#1771)
+  * Bug fix: downloading model with limited list of reactions and elements
+    downloaded also text areas (#1770)
+  * Bug fix: when CellDesigner species contained notes in both Species and Gene
+    tags the notes were improperly parsed and could cause issues on export
+    (#1772, #1772)
+  * Bug fix: when the last cell in the last column of overlay data entered in
+    the upload dialog is empty there was an unexpected (#1743)
+  * Bug fix: disable delete plugin button when removing plugin (#1766)
+  * Bug fix: removing non existing overlay caused an error (#1791)
+
+ -- Piotr Gawron <piotr.gawron@uni.lu>  Sat, 22 Oct 2022 11:00:00 +0200
+
+minerva (16.2.8) stable; urgency=medium
+  * Bug fix: missing content-type header in REST API documentation caused
+    issues with converter API (#1745, #1754, #1759, #1755)
+  * Bug fix: MINERVA_AUTH token in REST API documentation was sometimes
+    missing and sometimes it was unnecessary (#1744)
+  * Bug fix: deprecated "semantic-zoom" changed to
+    "semantic-zoom-contains-multiple-layouts" in REST API documentation for
+    project upload (#1754)
+  * Bug fix: export to SBML did not work with empty complexes containing the
+    same structural state (#1757, #1756)
+  * Bug fix: updating user plugin data did not work (#1739)
+  * Bug fix: legend was not visualized properly for mix of defined and
+    undefined colors in overlay (#1749)
+  * Bug fix: misleading "undefined maps" removed from submaps tab (#1703)
+
+ -- Piotr Gawron <piotr.gawron@uni.lu>  Fri, 09 Sep 2022 10:00:00 +0200
+
+minerva (16.2.7) stable; urgency=medium
+  * Bug fix: when providing problematic input file in REST API converter the
+    status code should be 400 (BAD REQUEST) instead of 500
+  * Bug fix: default curl content type (application/x-www-form-urlencoded)
+    caused issues when using converter API (#1734)
+
+ -- Piotr Gawron <piotr.gawron@uni.lu>  Thu, 21 Jul 2022 11:00:00 +0200
+
 minerva (16.2.6) stable; urgency=medium
-  * Bug fix: partial update on defaultCenterX and defaultCenterY and defaultZoomLevel
-    did not work
+  * Bug fix: partial update on defaultCenterX and defaultCenterY and
+    defaultZoomLevel did not work
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Thu, 7 Jul 2022 11:00:00 +0200
 
@@ -26,7 +108,7 @@ minerva (16.2.5) stable; urgency=medium
  -- Piotr Gawron <piotr.gawron@uni.lu>  Wed, 6 Jul 2022 16:00:00 +0200
 
 minerva (16.2.4) stable; urgency=medium
-  * Bug fix: rest api of uniprot.org changed
+  * Bug fix: rest API of UniProt changed
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Tue, 5 Jul 2022 14:00:00 +0200
 
@@ -35,7 +117,7 @@ minerva (16.2.3) stable; urgency=medium
     annotators (#1722)
   * Bug fix: modification residue id must start with a letter when exporting to
     CellDesigner
-  * Bug fix: expot to SBML did not work for cmaps that had two or more complexes
+  * Bug fix: export to SBML did not work for maps that had two or more complexes
     with the same children that had modification residues (#1720)
   * Bug fix: when providing invalid url in gene mapping proper error message is
     shown (#1723)
@@ -54,7 +136,7 @@ minerva (16.2.2) stable; urgency=medium
  -- Piotr Gawron <piotr.gawron@uni.lu>  Mon, 20 Jun 2022 12:00:00 +0200
 
 minerva (16.2.1) stable; urgency=medium
-  * Bug fix: Kegg annotator stopped working after kegg moved to https
+  * Bug fix: Kegg annotator stopped working after Kegg moved to https
   * Bug fix: General overlays were marked as editable even though they should
     not be (#1706, #1702)
   * Bug fix: searching for non existing chemical caused an error to be thrown
@@ -240,7 +322,7 @@ minerva (16.1.0) stable; urgency=medium
   * Bug fix: help dialog is closed automatically after Add Project dialog is
     closed (#1099)
   * Bug fix: root url must be valid url pointing to minerva instance (#1689)
-  * Bug fix: there were missing lines when exporting truncation/dissotiation
+  * Bug fix: there were missing lines when exporting truncation/dissociation
     reaction to GPML (#1676)
   * Bug fix: some SBML files were recognized as CellDesigner files (#1677)
   * Bug fix: reaction middle was not highlighted (#1637)
@@ -390,8 +472,8 @@ minerva (16.0.0) stable; urgency=medium
   * Small improvement: homomultimer information is provided in API (#1468)
   * Small improvement: missing info about species for SBML parsing warning
     (#1472)
-  * Small improvement: information about dimer in sbgn is provided only once
-    if the information is duplicated in sbgn data (#1358)
+  * Small improvement: information about dimer in SBGN is provided only once
+    if the information is duplicated in SBGN data (#1358)
   * Small improvement: glyph quality is improved (#1458)
   * Small improvement: search results are group by diagram (#1451)
   * Small improvement: "Failed to fetch" errors are reported in a way that
@@ -421,7 +503,7 @@ minerva (16.0.0) stable; urgency=medium
     caused issue (#1546)
   * Bug fix: search results were limited to 10 elements
   * Bug fix: Chrome autofill is disabled for "Search: " in admin panel tables
-  * Bug fix: search tab becomes active when drug/chemical/mirna result are
+  * Bug fix: search tab becomes active when drug/chemical/MiRNA result are
     available (#1491)
   * Bug fix: arrows without a "process" box had an irregular empty space in
     their lines (#1471)
@@ -434,7 +516,7 @@ minerva (16.0.0) stable; urgency=medium
   * Bug fix: removing plugin that does not exist anymore does not raise an error
     (#1289)
   * Bug fix: md5 hash function of plugin was not computed properly
-  * Bug fix: exported gpml for every compartment contained list of species name
+  * Bug fix: exported GPML for every compartment contained list of species name
     in the comment section
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Fri, 29 Oct 2021 13:00:00 +0200
@@ -479,14 +561,14 @@ minerva (15.1.1) stable; urgency=medium
   * Bug fix: zoom level change was not reflected in the url when submap was
     opened (#1338)
   * Bug fix: API call returning list of overlays returned for non existing
-    project returned access denied status insted Not Found (#1370)
-  * Bug fix: results for chembl targetting uniprot without gene name (for
+    project returned access denied status instead Not Found (#1370)
+  * Bug fix: results for chembl targetting UniProt without gene name (for
     example P0C2L1)  could crash caching (#1377)
   * Bug fix: removing non-existing project results in warning not an error
     message (#1367)
   * Bug fix: opening map in google maps without background resulted in
     unexpected error (#1416)
-  * Bug fix: normal user could not update tos information (#1419)
+  * Bug fix: normal user could not update ToS information (#1419)
   * Bug fix: and operator in SBGN-like view was not drawn (#1408)
   * Bug fix: export of overlayed map as an image did not respect overlay colors
    (#1417)
@@ -558,15 +640,15 @@ minerva (15.0.3) stable; urgency=medium
   * Bug fix: when there is a problem with minerva deployment on tomcat proper
     warning message is presented in admin panel (#1332)
   * Bug fix: API call updating user preferences did not handle properly
-    conflicts on new gui properties (#1326)
-  * Bug fix: "bqbiol:hasTaxon" relation type is not supported by CellDedigner
+    conflicts on new GUI properties (#1326)
+  * Bug fix: "bqbiol:hasTaxon" relation type is not supported by CellDesigner
     and is now transformed during export into something readable by
     CellDesigner (#1281)
   * Bug fix: concurrency issue that could happen rarely on first search of the
     map and put the project into "unsearchable" state is fixed (#1333)
-  * Bug fix: when edit project buton was clicked on project that was removed in
+  * Bug fix: when edit project button was clicked on project that was removed in
     another tab there was an error thrown (#1343)
-  * Bug fix: chebi and entrez annotations were incorrectly exported to GPML
+  * Bug fix: CHEBI and Entrez annotations were incorrectly exported to GPML
     (#1349)
   * Bug fix: exporting to GPML sometimes resulted in invalid modification point
     end for catalysis (#1350)
@@ -597,11 +679,11 @@ minerva (15.0.2) stable; urgency=medium
     not handled properly (#1281)
   * Bug fix: "bqmodel:isInstanceOf", "bqmodel:hasInstance",
     "bqbiol:hasProperty", "bqbiol:isPropertyOf" relation types are not
-    supported by CellDedigner and are now transformed during export into
+    supported by CellDesigner and are now transformed during export into
     something readable by CellDesigner (#1281)
   * Bug fix: at random time points there was an issue with cached data (#1323)
   * Bug fix: connection to DAPI timeouted sometimes which resulted in error
-    when checking for all chemicals for specfific protein (#1324)
+    when checking for all chemicals for specific protein (#1324)
   * Bug fix: complex/compartment with empty name was incorrectly exported to
     CellDesigner (#1310)
 
@@ -680,7 +762,7 @@ minerva (15.0.0) stable; urgency=medium
   * Small improvement: simple molecules in SBGN compliant view are drawn as
     ellipses not circles (#796)
   * Small improvement: uploaded map is automatically cached (#983)
-  * Small improvement: molart updated to version 1.5.0: Ability to show
+  * Small improvement: MolArt updated to version 1.5.0: Ability to show
     unobserved structure regions in the sequence view.
   * Small improvement: list of genomes is automatically refreshed during genome
     upload (#820)
@@ -717,7 +799,7 @@ minerva (15.0.0) stable; urgency=medium
   * Bug fix: newt use incorrect attributes when exporting render information
     that could not be parsed by minerva (#1127)
   * Bug fix: catalysis to protein was not parsed from SBGN file (#1116)
-  * Bug fix: antisenseRNA shape is inferred from SBGN when antisenseRNA text is
+  * Bug fix: antisense RNA shape is inferred from SBGN when antisense RNA text is
     present in glyph label (#1114)
   * Bug fix: export to SBGN sometimes crashed due to concurrency issues (#1126)
   * Bug fix: CellDesigner models where start and end point of reaction was the
@@ -766,9 +848,9 @@ minerva (14.0.13) stable; urgency=medium
 minerva (14.0.12) stable; urgency=medium
   * Bug fix: comments on submaps were not visible (#1230)
   * Bug fix: removing comment from submap did not work
-  * Bug fix: reaction name containing "<" character was exported inproperly to
+  * Bug fix: reaction name containing "<" character was exported improperly to
     CellDesigner (#1227)
-  * Bug fix: doi annotation was inproperly parsed from CellDesigner file and
+  * Bug fix: DOI annotation was improperly parsed from CellDesigner file and
     resulted in not clickable link (#1231)
   * Bug fix: when plugin data was too big 500 error was returned (#1232)
   * Bug fix: removing plugin in admin panel removes it from server permanently
@@ -777,7 +859,7 @@ minerva (14.0.12) stable; urgency=medium
  -- Piotr Gawron <piotr.gawron@uni.lu>  Mon, 11 May 2020 17:00:00 +0200
 
 minerva (14.0.11) stable; urgency=medium
-  * Bug fix: complex with no border was inproperly imported from CellDesigner
+  * Bug fix: complex with no border was improperly imported from CellDesigner
     (#1198)
   * Bug fix: export to CellDesigner deal with CellDesigner issue that does not
     allow compartment species alias to be shorter than 2 characters (#1204)
@@ -785,7 +867,7 @@ minerva (14.0.11) stable; urgency=medium
     minerva (#1202)
   * Bug fix: infinity value in kinetic parameter could not be parsed from
     CellDesigner file minerva (#1203)
-  * Bug fix: author list inproperly presented author data when some fields were
+  * Bug fix: author list improperly presented author data when some fields were
     missing (#1201)
   * Bug fix: refreshing minerva page with more than one plugin opened might
     led to an error due to race condition (#1197)
@@ -801,7 +883,7 @@ minerva (14.0.10) stable; urgency=medium
  -- Piotr Gawron <piotr.gawron@uni.lu>  Mon, 16 Mar 2020 14:00:00 +0200
 
 minerva (14.0.9) stable; urgency=medium
-  * Bug fix: simultanous export to SBML of more than one file could result in
+  * Bug fix: simultaneous export to SBML of more than one file could result in
     500 Internal Server Error (#1110)
   * Bug fix: refresh data overlay did not hide data overlays that were removed
     and selected (#1097)
@@ -832,7 +914,7 @@ minerva (14.0.9) stable; urgency=medium
 minerva (14.0.8) stable; urgency=medium
   * Bug fix: API didn't allow to upload plugins with local url (#1084,
     regression 14.0.7)
-  * Bug fix: upload of data overlay with two entries having different uniprot
+  * Bug fix: upload of data overlay with two entries having different UniProt
     identifier but pointing to the same gene crashed (#1083)
   * Bug fix: don't allow to remove plugin twice (#1081)
   * Bug fix: upload of SBML file with very short reaction length could produce
@@ -866,13 +948,13 @@ minerva (14.0.6) stable; urgency=medium
   * Bug fix: search by identifier didn't consider identifiers added by
     annotators (#1047)
   * Bug fix: if map has SHOW OVERVIEW, the legend/comment/clear were not
-    displayed at all (regresion 14.0.5, #1045)
+    displayed at all (regression 14.0.5, #1045)
   * Bug fix: when there is a problem with database during removing project,
     project removal doesn't hang (#1058)
   * Bug fix: coloring of the reaction wasn't applied to center of reaction
     (regression 14.0.0, #1057)
   * Bug fix: genetic variant overlay improperly processed elements identified
-    by miriam identifiers, like uniprot (#1059)
+    by miriam identifiers, like UniProt (#1059)
   * Bug fix: invalid information was provided for genetic variants overlay when
     map organism was defined (#1060)
 
@@ -881,7 +963,7 @@ minerva (14.0.6) stable; urgency=medium
 minerva (14.0.5) stable; urgency=medium
   * Bug fix: copy-paste of genetic-variant data overlay into Add overlay
     content dialog could crash upload (#1040)
-  * Bug fix: some annotators (like Cazy) were crashing on old installations
+  * Bug fix: some annotators (like CAZy) were crashing on old installations
     (#1029)
   * Bug fix: uploading a map that breaks postgres constraints hung upload of
     the project (#1028)
@@ -891,7 +973,7 @@ minerva (14.0.5) stable; urgency=medium
   * Bug fix: search for NADH drug resulted in drug with empty name (#1018)
   * Bug fix: export to SBML didn't handle properly arrows (#1015)
   * Bug fix: Font colour of text area was preserved in Empty view (#1014)
-  * Bug fix: exported sbml file always contain model identifier (#1013)
+  * Bug fix: exported SBML file always contain model identifier (#1013)
   * Bug fix: typo allel reverted to allele in overlay data (regression 14.0.0,
     #1012)
   * Bug fix: after loading/removing too many plugins it was impossible to load
@@ -906,7 +988,7 @@ minerva (14.0.4) stable; urgency=high
     due to problems with identifiers used by SBGN (#1006)
   * Bug fix: upload of data overlay with conflicting overlay types caused error
     (#998)
-  * Bug fix: upload of sbml file with protein modifications inside complex
+  * Bug fix: upload of SBML file with protein modifications inside complex
     crashed visualization (#966)
   * Bug fix: list of overlays for admin and curator included also other people
     overlays (regression 14.0.3, #1008)
@@ -918,7 +1000,7 @@ minerva (14.0.4) stable; urgency=high
 minerva (14.0.3) stable; urgency=medium
   * Bug fix: default zoom level on main map works even when x or y are
     undefined (#993)
-  * Bug fix: sbml parser had sometimes problems with combining layout and multi
+  * Bug fix: SBML parser had sometimes problems with combining layout and multi
     packages (#966)
   * Bug fix: parsing of CellDesigner files that contained substanceUnits could
     crash the upload (#985)
@@ -954,7 +1036,7 @@ minerva (14.0.2) stable; urgency=medium
  -- Piotr Gawron <piotr.gawron@uni.lu>  Wed, 15 Oct 2019 11:00:00 +0200
 
 minerva (14.0.1) stable; urgency=medium
-  * Bug fix: maps that were annotated using old Biocompendium annotator could
+  * Bug fix: maps that were annotated using old BioCompendium annotator could
     not load properly (#986)
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Wed, 15 Oct 2019 9:00:00 +0200
@@ -1018,7 +1100,7 @@ minerva (14.0.0) stable; urgency=medium
     (#936)
   * Bug fix: work on FF Private Window mode could cause logout or raise an
     error on when opening new tab with minerva (#892)
-  * Bug fix: fetching list of miRnas resulted sometimes in "Internal Server
+  * Bug fix: fetching list of MiRNAs resulted sometimes in "Internal Server
     Error" (#889)
   * Bug fix: edit project dialog verifies organism id  (#914)
   * Bug fix: all colors in boolean reaction (from CellDesigner) are processed
@@ -1092,7 +1174,7 @@ minerva (13.1.1) stable; urgency=medium
     inside compartment (#856)
   * Bug fix: searching for some drugs in chembl didn't provide any results even
     though that data exists, for instance 'DORLIMOMAB ARITOX' (#842)
-  * Bug fix: user wasn't logged out in all tabs when the log out event appeard
+  * Bug fix: user wasn't logged out in all tabs when the log out event appeared
     in only one of them (#847)
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Tue,  2 Jul 2019 19:00:00 +0200
@@ -1133,7 +1215,7 @@ minerva (13.1.0) stable; urgency=medium
     (#666)
   * Small improvement: list of projects is auto refreshed every 5 seconds if at
     least one of the project is uploading/removing (#610)
-  * Small improvement: passwords to email account and ldap are not sent over
+  * Small improvement: passwords to email account and LDAP are not sent over
     API (#732)
   * Small improvement: reactant/product/modifier specific colors are parsed
     properly from CellDesigner file (#597)
@@ -1142,7 +1224,7 @@ minerva (13.1.0) stable; urgency=medium
   * Small improvement: Info tab provides information about model annotations
     and submap tabs provide information about submaps annotations if applicable
     (#591)
-  * Small improvement: uploading sbml file should automatically discover a file
+  * Small improvement: uploading SBML file should automatically discover a file
     type (#784)
   * Small improvement: when plugin listeners crash the system notifies user
     about problem with a plugin (#767)
@@ -1157,19 +1239,19 @@ minerva (13.1.0) stable; urgency=medium
     SemanticZoomLevelTransparency (#801)
   * Small improvement: export/import from SBML support z-index in LAYOUT
     extension
-  * Bug fix: due to blocking of our requests from ctdbase the autocomplete for
+  * Bug fix: due to blocking of our requests from CTD base the autocomplete for
     this database is disabled
   * Bug fix: deprecated columns in data overlay are not visible to the end user
     (#827)
   * Bug fix: invalid color in data overlay provides proper feedback to the user
     (#822)
   * Bug fix: genetic variant overlay without name caused problems (#832)
-  * Bug fix: tair locus identifiers were used improperly - instead of id the
+  * Bug fix: Tair locus identifiers were used improperly - instead of id the
     name was used
   * Bug fix: plugin tab header wasn't properly resized after adding plugins
     that introduced second line for tab selection (#758)
   * Bug fix: invisible layer shouldn't be shown on the map (#813)
-  * Bug fix: list of availbale annotators is sorted alphabetically (#815)
+  * Bug fix: list of available annotators is sorted alphabetically (#815)
   * Bug fix: redirect url from export panel is fixed (#819)
   * Bug fix: allow to reupload the same file without closing add overlay dialog
     (#833)
@@ -1193,8 +1275,8 @@ minerva (13.1.0) stable; urgency=medium
     slightly separated from target phenotype (#664)
   * Bug fix: order of genomes in admin panel doesn't change after refreshing
     list of genomes (#761)
-  * Bug fix: fixing situation when Molart started with variation overlay not
-    having the aa change information
+  * Bug fix: fixing situation when MolArt started with variation overlay not
+    having the a change information
   * Bug fix: plugin contect element width is adjusted when link to tabs are
     wrapped in more than one line (#758)
   * Bug fix: export to CellDesigner preserve font size (#798)
@@ -1246,7 +1328,7 @@ minerva (12.2.2) stable; urgency=medium
  -- Piotr Gawron <piotr.gawron@uni.lu>  Tue, 9 Apr 2019 17:00:00 +0200
 
 minerva (12.2.1) stable; urgency=medium
-  * Bug fix: export of reaction colorsi in SBML is properly encoded (COPASI can
+  * Bug fix: export of reaction colors in SBML is properly encoded (COPASI can
     read colors properly) (#744)
   * Bug fix: removing active plugin didn't switch plugin tab to the next loaded
     plugin (#757)
@@ -1317,7 +1399,7 @@ minerva (12.2.0) stable; urgency=medium
     email account is provided
   * Small improvement: Plugin API allows to show/hide data overlays
   * Bug fix: Icons were sometimes not properly loaded on Safari (#661)
-  * Bug fix: migration scripts are compatibile with postgres 9.3 version that
+  * Bug fix: migration scripts are compatible with postgres 9.3 version that
     is default on Ubuntu 14 (#762)
   * Bug fix: update/remove button is disabled when user has no privileges for
     managing overlays (#742)
@@ -1403,7 +1485,7 @@ minerva (12.1.6) stable; urgency=medium
  -- Piotr Gawron <piotr.gawron@uni.lu>  Mon, 28 Jan 2019 16:00:00 +0200
 
 minerva (12.1.5) stable; urgency=medium
-  * Bug fix: Drugbank changed output format which crashed drug connector
+  * Bug fix: DrugBank changed output format which crashed drug connector
   * Bug fix: word wrapping fixed in overlay table for long overlay names
     in Firefox browser
 
@@ -1435,8 +1517,8 @@ minerva (12.1.3) stable; urgency=medium
 
 minerva (12.1.2) stable; urgency=medium
   * Bug fix: vmh annotations should be properly matching id entered in the input
-  * Bug fix: opacity was not working when highliting objects in plugins
-  * Bug fix: integer configurtion options (like SMTP_PORT) are properly
+  * Bug fix: opacity was not working when highlighting objects in plugins
+  * Bug fix: integer configuration options (like SMTP_PORT) are properly
     validated before saving
   * Bug fix: inside of reaction box wasn't properly aligned
   * Bug fix: too long data overlay name disturbed size of the map div and
@@ -1470,7 +1552,7 @@ minerva (12.1.0) stable; urgency=medium
   * Small improvement: plugins have to access information about active submap
   * Feature: genome browser with gene variants
   * Feature: support of all CellDesigner element modifications
-  * Feature: ldap authentication
+  * Feature: LDAP authentication
   * Feature: multicolored anchors for data overlays
   * Feature: minerva is distributed using rpm packages
   * Small improvement: annotations from RHEA are handled
@@ -1482,7 +1564,7 @@ minerva (12.1.0) stable; urgency=medium
     weren't provided properly
   * Bug fix: passwords in the configuration tab are hidden with '*'
   * Bug fix: user has access to transparency level when creating custom semantic
-    view (without this parametere functionality was very difficult to use)
+    view (without this parameter functionality was very difficult to use)
   * Bug fix: loading invalid plugin doesn't render empty div anymore
   * Bug fix: sorting of custom overlays was broken when description of overlay
     was present
@@ -1495,7 +1577,7 @@ minerva (12.1.0) stable; urgency=medium
   * Bug fix: double click on user add button disabled
   * Bug fix: privileges are mirrored correctly across different popups
   * Bug fix: plugin tab css fixed
-  * Bug fix: uploading sbml file with no ids in glyphs returned error that
+  * Bug fix: uploading SBML file with no ids in glyphs returned error that
     could not be easily understand
   * Bug fix: ds_store files in subfolders crashed zip upload
   * Bug fix: when creating new user default privileges were not filled
@@ -1564,7 +1646,7 @@ minerva (12.0.0) stable; urgency=medium
   * Feature: plugin API
   * Feature: all functionalities are provided via REST API
   * Feature: visualization of two (or more) overlaying results (like drug
-    target, mirna target) is highlighted with different icon
+    target, MiRNA target) is highlighted with different icon
   * Small improvement: email for account request contain configurable text
   * Small improvement: transparency level for data overlays is configurable
   * Small improvement: CellDesigner reactions of Modifier type are acceptable
@@ -1585,7 +1667,7 @@ minerva (12.0.0) stable; urgency=medium
   * Small improvement: Data overlays can submap column to differentiate between
     maps
   * Small improvement: search by chemical names is possible
-  * Small improvement: auto complete functionality for drugs, mirnas and
+  * Small improvement: auto complete functionality for drugs, MiRNAs and
     chemicals
   * Small improvement: columns value and type are not mutually exclusive in
     data overlays
@@ -1601,7 +1683,7 @@ minerva (12.0.0) stable; urgency=medium
   * Small improvement: submap reference in publication list
   * Small improvement: size of connection to database reduced to 90 (so default
     connection pool to postgres is not completely filled with minerva)
-  * Small improvement: visualization of sbml function improved (lambda
+  * Small improvement: visualization of SBML function improved (lambda
     expression removed from the definition)
   * Small improvement: handling of additional miriam types from BiGG ontology
   * Small improvement: configuration options are grouped in categories
@@ -1681,17 +1763,17 @@ minerva (11.0.7) stable; urgency=medium
   * Bug fix: there should be no problem with symlink when upgrading debian
     package
   * Bug fix: number of services changed API address to https: pmceurope
-    (pubmed), uniprot, ensembl, hgnc, recon, ctd database
+    (pubmed), UniProt, Ensembl, HGNC, recon, CTD database
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Thu, 18 Jan 2018 16:00:00 +0200
 
 minerva (11.0.6) stable; urgency=medium
-  * Bug fix: fix a bug when entering invalid mirna id
+  * Bug fix: fix a bug when entering invalid MiRNA id
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Thu, 14 Dec 2017 16:00:00 +0200
  
 minerva (11.0.5) stable; urgency=medium
-  * Bug fix: fix on connection to drugbank database
+  * Bug fix: fix on connection to DrugBank database
   * Bug fix: posttranslational modification data was sometimes unavailable
     in search results panel
 
@@ -1710,7 +1792,7 @@ minerva (11.0.3) stable; urgency=medium
   * Bug fix: links to invalid annotations were opening invalid web page
   * Bug fix: service resolving miriam resources doesn't work over http
     anymore
-  * Bug fix: chebi annotator doesn't work over http anymore
+  * Bug fix: CHEBI annotator doesn't work over http anymore
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Thu, 19 Oct 2017 13:50:00 +0200
 
@@ -1728,7 +1810,7 @@ minerva (11.0.0) stable; urgency=medium
 
   * Bug fix: security issue - access to specific map can be restricted
     by the user login
-  * Bug fix: sbgn import
+  * Bug fix: SBGN import
   * Bug fix: mesh connector
   * Rest API (documentation can be found here:
     https://git-r3lab.uni.lu/piotr.gawron/minerva/blob/master/README.md)
@@ -1746,7 +1828,7 @@ minerva (10.0.5) stable; urgency=medium
 
   * Bug fix: interacting drugs can be found for RNAs
   * Bug fix: error handling improved on map upload
-  * Bug fix: taxonomy ncbi server switched to https
+  * Bug fix: taxonomy NCBI server switched to https
   * Overlay presents description field if possible
 
 
@@ -1774,7 +1856,7 @@ minerva (10.0.3) stable; urgency=medium
 
 minerva (10.0.2) stable; urgency=medium
 
-  * Bug fix: markers for mirna targets visibility
+  * Bug fix: markers for MiRNA targets visibility
 
  -- Piotr Gawron <piotr.gawron@uni.lu>  Thu, 29 Sep 2016 10:01:16 +0200
 
@@ -1843,15 +1925,15 @@ minerva (6) stable; urgency=low
   * Galaxy connector
   * Miriam types report
   * Advanced annotation options
-  * Uniprot annotation module
+  * UniProt annotation module
   * Customized validation of miriam annotations
   * Recon annotation service
   * Bug fix: Data autofill problem in user management
   * Bug fix: User privileges for adding project
   * Bug fix: Problem with some miriam entries in RDF format
   * Bug fix: Reporting of drawing problems
-  * Bug fix: Visualization of posttranslationa modification
-  * Bug fix: Drugbank problem after update of Drugbank interface
+  * Bug fix: Visualization of posttranslational modification
+  * Bug fix: DrugBank problem after update of DrugBank interface
   * Bug fix: Session scope fixed (browsing many maps at the same time)
   * Bug fix: Asynchronous removing/adding maps
   * Bug fix: Export to CellDesigner rarely produced corrupted CellDesigner file
@@ -1879,12 +1961,12 @@ minerva (5) stable; urgency=low
 minerva (4) stable; urgency=low
 
   * Export of the part of the map into CellDesigner file
-  * Logo files managable via config webpage
+  * Logo files manageable via config webpage
   * Import data from GO
   * Custom overlay upload
   * Additional structural information imported from annotation service
   * Bug fix: Fonts and lines in hierarchical view
-  * Bug fix: Visualization of residues in rna, antisense rna, proteins
+  * Bug fix: Visualization of residues in RNA, antisense RNA, proteins
   * Bug fix: Problem with touching bubbles on touch interface
   * Bug fix: Problem with special UTF-8 characters in CellDesigner file
   * Bug fix: Problem with users and session expire
diff --git a/CellDesigner-plugin/.project b/CellDesigner-plugin/.project
index 7644e74c95ccb96514302b8fac71b10af8d5df71..5a8593cc67bc0f4a56843ed5043137b7b68fdcec 100644
--- a/CellDesigner-plugin/.project
+++ b/CellDesigner-plugin/.project
@@ -11,8 +11,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (12).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/annotation/.project b/annotation/.project
index 5dd65eed5eb071becf35fe19a7e9aaab629db307..cc8da93dfb1360118ff0a1e84298e27f0072081e 100644
--- a/annotation/.project
+++ b/annotation/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (3).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/PubmedParserImpl.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/PubmedParserImpl.java
index 6ae3a6ba0480131109c5bb701b2e6811cdd68a0c..69012b6163542ff096c10681f0e6c47b2eabbcb7 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/PubmedParserImpl.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/PubmedParserImpl.java
@@ -212,7 +212,7 @@ public class PubmedParserImpl extends CachableInterface implements PubmedParser
     if (id == null) {
       return null;
     }
-    return getPubmedArticleById(Integer.valueOf(id.trim()));
+    return getPubmedArticleById(Integer.valueOf(id.replaceAll("[^0-9.]", "").trim()));
   }
 
   /**
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/EnsemblAnnotatorImpl.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/EnsemblAnnotatorImpl.java
index 07b20b8a17d985153ed42120207f2d9ad39382ff..f7e7a33ac97e4fa897f31e7e1244e17a5385de41 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/EnsemblAnnotatorImpl.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/EnsemblAnnotatorImpl.java
@@ -46,7 +46,7 @@ public class EnsemblAnnotatorImpl extends ElementAnnotator implements EnsemblAnn
   /**
    * Version of the rest API that is supported by this annotator.
    */
-  static final String SUPPORTED_VERSION = "15.1";
+  static final String SUPPORTED_VERSION = "15.3";
 
   /**
    * Url address of ensembl restful service.
@@ -128,7 +128,8 @@ public class EnsemblAnnotatorImpl extends ElementAnnotator implements EnsemblAnn
   }
 
   @Override
-  public boolean annotateElement(final BioEntityProxy element, final MiriamData identifier, final AnnotatorData parameters)
+  public boolean annotateElement(final BioEntityProxy element, final MiriamData identifier,
+      final AnnotatorData parameters)
       throws AnnotatorException {
     if (identifier.getDataType().equals(MiriamType.ENSEMBL)) {
       String query = REST_SERVICE_URL + identifier.getResource() + URL_SUFFIX;
diff --git a/commons/.project b/commons/.project
index 2d0eff72f8eac2b33561e093d44e9ff86b84e90d..a26883597d46ac49b74ce855ae9b1c945e26ee8d 100644
--- a/commons/.project
+++ b/commons/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (1).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java b/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java
index 30436f65e06122abcb38aed21043928fb5df813f..1a5b7a15675b5f829073b668362ee3c2882f499e 100644
--- a/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java
+++ b/commons/src/main/java/lcsb/mapviewer/common/XmlParser.java
@@ -101,18 +101,27 @@ public final class XmlParser {
    * @return node from nodes list with the tagName name, <b>null</b> if such node
    *         doesn't exist
    */
-  public static Node getNode(final String tagName, final NodeList nodes) {
+  public static Node getNode(final String tagName, final NodeList nodes, final boolean ignoreNamespace) {
     for (int x = 0; x < nodes.getLength(); x++) {
       Node node = nodes.item(x);
       if (node.getNodeType() == Node.ELEMENT_NODE) {
         if (node.getNodeName().equalsIgnoreCase(tagName)) {
           return node;
         }
+        if (ignoreNamespace) {
+          if (node.getNodeName().toLowerCase().endsWith(":" + tagName.toLowerCase())) {
+            return node;
+          }
+        }
       }
     }
     return null;
   }
 
+  public static Node getNode(final String tagName, final NodeList nodes) {
+    return getNode(tagName, nodes, false);
+  }
+
   /**
    * Method returns the child node of xml 'parentNode' with 'tagName' name. If
    * node could not be found then null is returned.
@@ -301,8 +310,8 @@ public final class XmlParser {
   }
 
   /**
-   * This method transform color encoded in string (final CellDesigner format) into
-   * Color.
+   * This method transform color encoded in string (final CellDesigner format)
+   * into Color.
    * 
    * @param color
    *          string representing color
diff --git a/converter-CellDesigner/.project b/converter-CellDesigner/.project
index cf03151587cdb2953630e7b185b372732c08243e..bf1a13a878d0387dab56dd985e09c455750a7820 100644
--- a/converter-CellDesigner/.project
+++ b/converter-CellDesigner/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (5).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/annotation/RestAnnotationParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/annotation/RestAnnotationParser.java
index c831e934e97a6e0224a3a118bafbf24162e431bd..e732d65f57e509eb6e3cf272a47bd67704691fe7 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/annotation/RestAnnotationParser.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/annotation/RestAnnotationParser.java
@@ -445,11 +445,11 @@ public class RestAnnotationParser {
       throw new InvalidArgumentException("Invalid notes node");
     }
 
-    Node htmlNode = XmlParser.getNode("html", node.getChildNodes());
+    Node htmlNode = XmlParser.getNode("html", node.getChildNodes(), true);
     if (htmlNode == null) {
       notes = XmlParser.nodeToString(node).trim();
     } else {
-      Node bodyNode = XmlParser.getNode("body", htmlNode.getChildNodes());
+      Node bodyNode = XmlParser.getNode("body", htmlNode.getChildNodes(), true);
       if (bodyNode != null) {
         notes = XmlParser.nodeToString(bodyNode).trim();
       }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java
index cd1ec4aa44ea0f957c3430fee38600c30953cafc..f2343a619a997e887aebf3648ae7294657e5789f 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java
@@ -187,7 +187,7 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement<
         setNotes(species.getNotes());
       } else if (!string1.toLowerCase().contains(string2.toLowerCase())) {
         // insert new information
-        setNotes(string2 + getNotes());
+        setNotes(string2 + "\n" + getNotes());
       }
     }
 
@@ -597,7 +597,8 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement<
   public void updateModelElementAfterLayoutAdded(final Species element) {
   }
 
-  protected StructuralState createStructuralState(final Species species, final String structuralState, final Double sourceAngle) {
+  protected StructuralState createStructuralState(final Species species, final String structuralState,
+      final Double sourceAngle) {
     if (structuralState == null) {
       return null;
     }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java
index 40c94d91091354b33823f42e657c518a859c6b4d..91b9da293c501fa15498ff2961906258824156d4 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java
@@ -1044,4 +1044,13 @@ public class CellDesignerXmlParserTest extends CellDesignerTestFunctions {
     assertNull(((Species) model2.getElementByElementId(protein2.getElementId())).getSubstanceUnits());
   }
 
+  @Test
+  public void testNamespace() throws Exception {
+    CellDesignerXmlParser parser = new CellDesignerXmlParser();
+    Model model = parser
+        .createModel(new ConverterParams().filename("testFiles/problematic/namespace.xml")
+            .sizeAutoAdjust(false));
+    assertEquals("", model.getNotes());
+  }
+
 }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesTest.java
index 959f74e50413a9aedf2d1f997fed50ad8bf4738a..6bbe527a54a7d16888ed0cc31ea5d57499d563d3 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesTest.java
@@ -2,6 +2,7 @@ package lcsb.mapviewer.converter.model.celldesigner.structure;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -182,6 +183,20 @@ public class SpeciesTest extends CellDesignerTestFunctions {
     assertEquals(0, warningsCount);
   }
 
+  @Test
+  public void testUpdateNotes() {
+    String notes1 = "XXX A";
+    String notes2 = "Notes B";
+    CellDesignerSpecies<?> species = new CellDesignerSpecies<GenericProtein>();
+    species.setNotes(notes1);
+    CellDesignerSpecies<?> species2 = new CellDesignerSpecies<GenericProtein>();
+    species2.setNotes(notes2);
+    species.update(species2);
+    assertEquals(0, getWarnings().size());
+    assertNotEquals(notes1 + notes2, species.getNotes());
+    assertNotEquals(notes2 + notes1, species.getNotes());
+  }
+
   @Test(expected = InvalidArgumentException.class)
   public void testSetInvalidAmount() {
     CellDesignerSpecies<?> species = new CellDesignerSpecies<GenericProtein>();
diff --git a/converter-CellDesigner/testFiles/problematic/namespace.xml b/converter-CellDesigner/testFiles/problematic/namespace.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fe6a7035d60451dbea093c7281e93e46867af10a
--- /dev/null
+++ b/converter-CellDesigner/testFiles/problematic/namespace.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" level="2" version="4">
+	<model>
+		<notes>
+			<html:html>
+				<html:head>
+					<html:title />
+				</html:head>
+				<html:body />
+			</html:html>
+		</notes>
+		<annotation>
+			<celldesigner:extension>
+				<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+				<celldesigner:modelDisplay sizeX="600" sizeY="400" />
+				<celldesigner:listOfCompartmentAliases />
+				<celldesigner:listOfComplexSpeciesAliases />
+				<celldesigner:listOfSpeciesAliases />
+				<celldesigner:listOfGroups />
+				<celldesigner:listOfProteins />
+				<celldesigner:listOfGenes />
+				<celldesigner:listOfRNAs />
+				<celldesigner:listOfAntisenseRNAs />
+				<celldesigner:listOfLayers />
+				<celldesigner:listOfBlockDiagrams />
+			</celldesigner:extension>
+		</annotation>
+		<listOfUnitDefinitions>
+			<unitDefinition metaid="substance" id="substance" name="substance">
+				<listOfUnits>
+					<unit metaid="CDMT00001" kind="mole" />
+				</listOfUnits>
+			</unitDefinition>
+			<unitDefinition metaid="volume" id="volume" name="volume">
+				<listOfUnits>
+					<unit metaid="CDMT00002" kind="litre" />
+				</listOfUnits>
+			</unitDefinition>
+			<unitDefinition metaid="area" id="area" name="area">
+				<listOfUnits>
+					<unit metaid="CDMT00003" kind="metre" exponent="2" />
+				</listOfUnits>
+			</unitDefinition>
+			<unitDefinition metaid="length" id="length" name="length">
+				<listOfUnits>
+					<unit metaid="CDMT00004" kind="metre" />
+				</listOfUnits>
+			</unitDefinition>
+			<unitDefinition metaid="time" id="time" name="time">
+				<listOfUnits>
+					<unit metaid="CDMT00005" kind="second" />
+				</listOfUnits>
+			</unitDefinition>
+		</listOfUnitDefinitions>
+		<listOfCompartments>
+			<compartment metaid="default" id="default" size="1" units="volume" />
+		</listOfCompartments>
+	</model>
+</sbml>
\ No newline at end of file
diff --git a/converter-SBGNML/.project b/converter-SBGNML/.project
index cee08a22554f452159725e87277b35fcc4639be8..339d4b3234ce97f358d444c1376d2ff74e3a74dd 100644
--- a/converter-SBGNML/.project
+++ b/converter-SBGNML/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (7).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/converter-graphics/.project b/converter-graphics/.project
index a0ccbe6c1b2791d99338688883a6465b946a257b..98b2440a4a066452a6a62999018c06507ebf7ccc 100644
--- a/converter-graphics/.project
+++ b/converter-graphics/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (6).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/LegendGenerator.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/LegendGenerator.java
index a8a566c09f89bd3e3b4003ada52d9cd6634936e4..8cb9369e1c61bcef2ef92a171bec4e6b95c39ac0 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/LegendGenerator.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/LegendGenerator.java
@@ -172,7 +172,11 @@ public class LegendGenerator {
     Font oldFont = graphics.getFont();
     Set<Color> colorSet = new HashSet<>();
     for (DataOverlayEntry entry : overlay.getEntries()) {
-      colorSet.add(((GenericDataOverlayEntry) entry).getColor());
+      Color color = ((GenericDataOverlayEntry) entry).getColor();
+      if (color == null) {
+        color = colorExtractor.getSimpleColor();
+      }
+      colorSet.add(color);
     }
     List<Color> colors = new ArrayList<>(colorSet);
     colors.sort(new Comparator<Color>() {
diff --git a/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/LegendGeneratorTest.java b/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/LegendGeneratorTest.java
index 297cf345cb743d30d5ecebdc449bd169ae6f93b1..a866896e3033649db32bb5e939bdf61d0806b130 100644
--- a/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/LegendGeneratorTest.java
+++ b/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/LegendGeneratorTest.java
@@ -69,6 +69,24 @@ public class LegendGeneratorTest extends GraphicsTestFunctions {
     file.delete();
   }
 
+  @Test
+  public void testGenericWithNullColor() throws IOException {
+    DataOverlay overlay = new DataOverlay();
+    GenericDataOverlayEntry entry = new GenericDataOverlayEntry();
+    entry.setColor(Color.YELLOW);
+    overlay.addEntry(entry);
+    entry = new GenericDataOverlayEntry();
+    entry.setColor(null);
+    entry.setElementId("re1");
+    overlay.addEntry(entry);
+    generator.savetToPng(overlay, extractor, "tmp.png");
+    File file = new File("tmp.png");
+    assertTrue(file.exists());
+    Mockito.verify(generator, times(1)).generateGenericLegendByColor(any(), any(), any());
+    // Desktop.getDesktop().open(file);
+    file.delete();
+  }
+
   @Test
   public void testGenetic() throws IOException {
     DataOverlay overlay = new DataOverlay();
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/extension/multi/MultiPackageNamingUtils.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/extension/multi/MultiPackageNamingUtils.java
index 51873300ec19d791e123d2ea60757839c9f24513..1f10d6b1ec3840613b0ea585ccc4ef327d47cf7d 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/extension/multi/MultiPackageNamingUtils.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/extension/multi/MultiPackageNamingUtils.java
@@ -66,10 +66,6 @@ public final class MultiPackageNamingUtils {
     return feature.getIdPrefix() + getSpeciesTypeId(element).replace("minerva_species_type_", "");
   }
 
-  public static String getFeatureId(final Species element, final BioEntityFeature feature) {
-    return getFeatureId(element, feature);
-  }
-
   public static boolean isFeatureId(final String featureTypeId, final BioEntityFeature feature) {
     return featureTypeId.startsWith(feature.getIdPrefix());
   }
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java
index 1ce0aecbe8b37f665cf6c0af8792148828265c70..dfca779a628a04ce66925f6427769e58745f53de 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java
@@ -488,6 +488,9 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j
       multiDistinguisher += "\n" + element.getActivity();
       multiDistinguisher += "\n" + element.getCharge();
       multiDistinguisher += "\n" + element.getHomodimer();
+      if (element instanceof Complex) {
+        multiDistinguisher += "\n" + element.getElementId();
+      }
     }
     String result = element.getClass().getSimpleName() + "\n" + annotationNames + "\n" + element.getName() + "\n"
         + compartmentName + "\n"
diff --git a/converter-sbml/testFiles/cd_for_multi/equal_complexes_with_structural_state.xml b/converter-sbml/testFiles/cd_for_multi/equal_complexes_with_structural_state.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4bb3a99c2282847c176786a1a224d92acd518be4
--- /dev/null
+++ b/converter-sbml/testFiles/cd_for_multi/equal_complexes_with_structural_state.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="Axonal_remodelling" id="Axonal_remodelling">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="6000" sizeY="2000"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases>
+<celldesigner:complexSpeciesAlias id="csa18" species="s12096">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="3391.3334686147173" y="453.18641774891717" w="130.0" h="50.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:backupSize w="0.0" h="0.0"/>
+<celldesigner:backupView state="none"/>
+<celldesigner:structuralState angle="1.5707963267948966"/>
+<celldesigner:usualView>
+<celldesigner:boxSize width="130.0" height="50.0"/>
+<celldesigner:singleLine width="2.0"/>
+<celldesigner:paint color="fff7f7f7" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="2.0"/>
+<celldesigner:paint color="fff7f7f7" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:complexSpeciesAlias>
+<celldesigner:complexSpeciesAlias id="csa24" species="s12096">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="4074.6971049783497" y="615.6409632034627" w="130.0" h="50.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:backupSize w="0.0" h="0.0"/>
+<celldesigner:backupView state="none"/>
+<celldesigner:structuralState angle="1.5707963267948966"/>
+<celldesigner:usualView>
+<celldesigner:boxSize width="130.0" height="50.0"/>
+<celldesigner:singleLine width="2.0"/>
+<celldesigner:paint color="fff7f7f7" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="2.0"/>
+<celldesigner:paint color="fff7f7f7" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:complexSpeciesAlias>
+</celldesigner:listOfComplexSpeciesAliases>
+<celldesigner:listOfSpeciesAliases/>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins/>
+<celldesigner:listOfGenes/>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00180" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00181" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00182" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00183" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00184" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s12096" id="s12096" name="filamentous actin" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>COMPLEX</celldesigner:class>
+<celldesigner:hypothetical>true</celldesigner:hypothetical>
+<celldesigner:name>filamentous actin</celldesigner:name>
+<celldesigner:state>
+<celldesigner:listOfStructuralStates>
+<celldesigner:structuralState structuralState="ADP"/>
+</celldesigner:listOfStructuralStates>
+</celldesigner:state>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter/.project b/converter/.project
index 129ec9da5c64d938f92db650d7a107e1ecfb58fc..305714127019af79159400ec54675e21ef291964 100644
--- a/converter/.project
+++ b/converter/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (4).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java
index d45ef7e7a449fbfce1fa1ed92c60f44585db84f5..b32fd50e3cba1e864ad7dab3708b26c6cb86907c 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/ComplexZipConverter.java
@@ -31,6 +31,7 @@ import lcsb.mapviewer.converter.zip.ModelZipEntryFile;
 import lcsb.mapviewer.converter.zip.ZipEntryFile;
 import lcsb.mapviewer.converter.zip.ZipEntryFileFactory;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
+import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
 import lcsb.mapviewer.model.map.model.ElementSubmodelConnection;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
@@ -56,8 +57,7 @@ import lcsb.mapviewer.model.overlay.InvalidDataOverlayException;
 public class ComplexZipConverter {
 
   /**
-   * Size of the buffer used for accessing single chunk of data from input
-   * stream.
+   * Size of the buffer used for accessing single chunk of data from input stream.
    */
   private static final int BUFFER_SIZE = 1024;
 
@@ -94,8 +94,8 @@ public class ComplexZipConverter {
    * Creates complex {@link Model} that contains submaps.
    * 
    * @param params
-   *          {@link ComplexZipConverterParams object} with information about
-   *          data from which result is going to be created
+   *          {@link ComplexZipConverterParams object} with information about data
+   *          from which result is going to be created
    * @return complex {@link Model} created from input data
    * @throws InvalidInputDataExecption
    *           thrown when there is a problem with accessing input data
@@ -258,8 +258,8 @@ public class ComplexZipConverter {
   }
 
   /**
-   * This method validates if information about model and submodels in the
-   * params are sufficient. If not then appropriate exception will be thrown.
+   * This method validates if information about model and submodels in the params
+   * are sufficient. If not then appropriate exception will be thrown.
    * 
    * @param params
    *          parameters to validate
@@ -356,6 +356,18 @@ public class ComplexZipConverter {
     ByteArrayInputStream baos = new ByteArrayInputStream(fileEntry.getFileContent());
     try {
       layout.addEntries(reader.readColorSchema(baos, parameters));
+
+      if (colorSchemaType == DataOverlayType.GENETIC_VARIANT) {
+        String genomeVersion = parameters.get(ZipEntryFileFactory.LAYOUT_HEADER_PARAM_GENOME_VERSION);
+        ReferenceGenomeType genomeType = ReferenceGenomeType.UCSC;
+        if (parameters.get(ZipEntryFileFactory.LAYOUT_HEADER_PARAM_GENOME_TYPE) != null) {
+          genomeType = ReferenceGenomeType
+              .valueOf(parameters.get(ZipEntryFileFactory.LAYOUT_HEADER_PARAM_GENOME_TYPE));
+        }
+        layout.setGenomeType(genomeType);
+        layout.setGenomeVersion(genomeVersion);
+      }
+
     } catch (final InvalidDataOverlayException e) {
       throw new InvalidInputDataExecption("Data overlay is invalid", e);
     }
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 9998423f73d13a2197ed4fdcfe58f88e5569c6d3..cf3e453212c83a87884d05544b8b2986b4cf621e 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -2126,6 +2126,17 @@ ServerConnector.getReactions = function (params) {
   });
 };
 
+/**
+ *
+ * @param {number} [params.modelId]
+ * @param {number[]} [params.ids]
+ * @param {number[]} [params.includedCompartmentIds]
+ * @param {number[]} [params.excludedCompartmentIds]
+ * @param {string[]} [params.columns]
+ * @param {string} [params.projectId]
+ * @param {string} [params.type]
+ * @returns {*}
+ */
 ServerConnector.getAliases = function (params) {
   var self = this;
   var queryParams = {
@@ -2150,7 +2161,10 @@ ServerConnector.getAliases = function (params) {
   };
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    if (filterParams.id.length > self.MAX_NUMBER_OF_IDS_IN_GET_QUERY) {
+    if (filterParams.id.length > self.MAX_NUMBER_OF_IDS_IN_GET_QUERY
+      || filterParams.excludedCompartmentIds.length > self.MAX_NUMBER_OF_IDS_IN_GET_QUERY
+      || filterParams.includedCompartmentIds.length > self.MAX_NUMBER_OF_IDS_IN_GET_QUERY
+    ) {
       return self.sendPostRequest(self.getAliasesUrl(queryParams), filterParams);
     } else {
       return self.sendGetRequest(self.getAliasesUrl(queryParams, filterParams));
diff --git a/frontend-js/src/main/js/gui/AddOverlayDialog.js b/frontend-js/src/main/js/gui/AddOverlayDialog.js
index ba42107154a7879db4ca909f674df77269c367c4..a827253a285ae1be316c0a5798f2bd6a3467dd15 100644
--- a/frontend-js/src/main/js/gui/AddOverlayDialog.js
+++ b/frontend-js/src/main/js/gui/AddOverlayDialog.js
@@ -225,8 +225,7 @@ AddOverlayDialog.prototype.getFileContent = function () {
   var contentInput = $("[name='overlay-content']", self.getElement())[0];
 
   if (contentInput.value !== undefined && contentInput.value !== null) {
-    contentInput.value = contentInput.value.trim();
-    if (contentInput.value !== "") {
+    if (contentInput.value.trim() !== "") {
       self.setFileContent(contentInput.value);
     }
   }
diff --git a/frontend-js/src/main/js/gui/admin/PluginAdminPanel.js b/frontend-js/src/main/js/gui/admin/PluginAdminPanel.js
index d9a9f8c53fa8206358aa11373d99e93e85e4b64e..c813ae5c8fa8496c0f593af9fc7ab792284d920b 100644
--- a/frontend-js/src/main/js/gui/admin/PluginAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/PluginAdminPanel.js
@@ -89,6 +89,7 @@ PluginAdminPanel.prototype._createGui = function () {
       input: false
     }).then(function (param) {
       if (param.status) {
+        $(button).prop('disabled', true);
         return self.getServerConnector().removePlugin({hash: $(button).attr("data")}).catch(function (error) {
           if (error instanceof NetworkError && error.statusCode === HttpStatus.NOT_FOUND) {
             GuiConnector.warn("Plugin does not exist anymore");
@@ -96,6 +97,7 @@ PluginAdminPanel.prototype._createGui = function () {
             throw error;
           }
         }).finally(function () {
+          $(button).prop('disabled', false);
           return self.onRefreshClicked();
         });
       }
diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
index 36bcad174e7394b7946e326e54f97833251616b9..454a86cbb4ba16be13ae9d397723c37d222fa1f4 100644
--- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
+++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
@@ -601,14 +601,17 @@ GuiUtils.prototype.createSubMapLink = function (params) {
   var result = Functions.createElement({type: "div", className: params.className});
   if (params.mapId !== undefined) {
     var button = document.createElement("button");
-    var model = self.getMap().getSubmapById(params.mapId).getModel();
-
-    button.innerHTML = model.getName();
-    button.onclick = function () {
-      return self.getMap().openSubmap(params.mapId);
-    };
-    result.appendChild(this.createLabel(params.label));
-    result.appendChild(button);
+    var submap = self.getMap().getSubmapById(params.mapId);
+    if (submap !== null) {
+      var model = submap.getModel();
+
+      button.innerHTML = model.getName();
+      button.onclick = function () {
+        return self.getMap().openSubmap(params.mapId);
+      };
+      result.appendChild(this.createLabel(params.label));
+      result.appendChild(button);
+    }
   }
   return result;
 };
diff --git a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
index a18c3f54815f1da5354eaf603c46204271391c78..7d7d028d03bd4c126a9c7f7683e9297de32cfc5c 100644
--- a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
@@ -9,6 +9,7 @@ var AddOverlayDialog = require('../AddOverlayDialog');
 var Panel = require('../Panel');
 var PanelControlElementType = require('../PanelControlElementType');
 var ValidationError = require('../../ValidationError');
+var NetworkError = require('../../NetworkError');
 
 var GuiConnector = require('../../GuiConnector');
 // noinspection JSUnusedLocalSymbols
@@ -526,7 +527,15 @@ OverlayPanel.prototype.openEditOverlayDialog = function (overlay) {
           GuiConnector.showProcessing("Removing");
           return self.removeOverlay(overlay).then(function () {
             $(windowSelf).dialog("close");
-          }).catch(GuiConnector.alert).finally(function () {
+          }).catch(function (error) {
+            if (error instanceof NetworkError && error.statusCode === 404) {
+              GuiConnector.warn("Overlay has been already removed.");
+              $(windowSelf).dialog("close");
+              return self.refresh();
+            } else {
+              GuiConnector.alert(error);
+            }
+          }).finally(function () {
             GuiConnector.hideProcessing();
           });
         }
diff --git a/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js b/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js
index 0888efa83975f935482f9401c16a57a17c0558b0..496c5d7e78f87d2ab4f3f3b316e4d6cc94926971 100644
--- a/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js
@@ -184,7 +184,7 @@ SubmapPanel.prototype.init = function () {
     for (i = 0; i < types.length; i++) {
       var type = types[i];
       var tableName = type + " submaps";
-      if (type === "UNKNOWN") {
+      if (type === "UNKNOWN" || type === undefined || type === null) {
         tableName = ""
       }
       modelsByType[type].sort(function (modelA, modelB) {
diff --git a/frontend-js/src/main/js/map/data/GeneVariant.js b/frontend-js/src/main/js/map/data/GeneVariant.js
index b38277db7aea575b970ac4deac261623c04bdd86..d052b9894134767b61e39360a8b1e38793270241 100644
--- a/frontend-js/src/main/js/map/data/GeneVariant.js
+++ b/frontend-js/src/main/js/map/data/GeneVariant.js
@@ -1,30 +1,45 @@
 "use strict";
 
+/**
+ * @typedef GeneVariantOptions
+ * @property {number} position
+ * @property {string} originalDna
+ * @property {string} modifiedDna
+ * @property {string} referenceGenomeType
+ * @property {string} referenceGenomeVersion
+ * @property {string} contig
+ * @property {string} [aminoAcidChange]
+ * @property {null|string} [allelFrequency]
+ * @property {null|string} [variantIdentifier]
+ */
+
 /**
  *
- * @param {Object} javaObject
- * @param {number} javaObject.position
- * @param {string} javaObject.originalDna
- * @param {string} javaObject.modifiedDna
- * @param {string} javaObject.referenceGenomeType
- * @param {string} javaObject.referenceGenomeVersion
- * @param {string} javaObject.contig
- * @param {string} [javaObject.aminoAcidChange]
- * @param {null|string} [javaObject.allelFrequency]
- * @param {null|string} [javaObject.variantIdentifier]
- *
+ * @param {GeneVariantOptions|GeneVariant} javaObject
  * @constructor
- */
+ * */
 function GeneVariant(javaObject) {
-  this.setPosition(javaObject.position);
-  this.setOriginalDna(javaObject.originalDna);
-  this.setModifiedDna(javaObject.modifiedDna);
-  this.setReferenceGenomeType(javaObject.referenceGenomeType);
-  this.setReferenceGenomeVersion(javaObject.referenceGenomeVersion);
-  this.setContig(javaObject.contig);
-  this.setAllelFrequency(javaObject.allelFrequency);
-  this.setVariantIdentifier(javaObject.variantIdentifier);
-  this.setAminoAcidChange(javaObject.aminoAcidChange);
+  if (javaObject instanceof GeneVariant) {
+    this.setPosition(javaObject.getPosition());
+    this.setOriginalDna(javaObject.getOriginalDna());
+    this.setModifiedDna(javaObject.getModifiedDna());
+    this.setReferenceGenomeType(javaObject.getReferenceGenomeType());
+    this.setReferenceGenomeVersion(javaObject.getReferenceGenomeVersion());
+    this.setContig(javaObject.getContig());
+    this.setAllelFrequency(javaObject.getAllelFrequency());
+    this.setVariantIdentifier(javaObject.getVariantIdentifier());
+    this.setAminoAcidChange(javaObject.getAminoAcidChange());
+  } else {
+    this.setPosition(javaObject.position);
+    this.setOriginalDna(javaObject.originalDna);
+    this.setModifiedDna(javaObject.modifiedDna);
+    this.setReferenceGenomeType(javaObject.referenceGenomeType);
+    this.setReferenceGenomeVersion(javaObject.referenceGenomeVersion);
+    this.setContig(javaObject.contig);
+    this.setAllelFrequency(javaObject.allelFrequency);
+    this.setVariantIdentifier(javaObject.variantIdentifier);
+    this.setAminoAcidChange(javaObject.aminoAcidChange);
+  }
 }
 
 /**
@@ -109,7 +124,7 @@ GeneVariant.prototype.getContig = function () {
 
 /**
  *
- * @param {string} allelFrequency
+ * @param {string|number} allelFrequency
  */
 GeneVariant.prototype.setAllelFrequency = function (allelFrequency) {
   if (allelFrequency === null) {
diff --git a/frontend-js/src/main/js/map/data/LayoutAlias.js b/frontend-js/src/main/js/map/data/LayoutAlias.js
index f313a307967cec55f930fed581b16d10049f7a43..ea6b0fc4780dd888407b85797968933bd45b2e29 100644
--- a/frontend-js/src/main/js/map/data/LayoutAlias.js
+++ b/frontend-js/src/main/js/map/data/LayoutAlias.js
@@ -2,43 +2,63 @@
 
 var GeneVariant = require('./GeneVariant');
 
+/**
+ * @typedef LayoutAliasOptions
+ * @property {number} idObject
+ * @property {number} [value]
+ * @property {{rgb:number}} [color]
+ * @property {number} modelId
+ * @property {string} [description]
+ * @property {number} [uniqueId]
+ * @property {string} [type=LayoutAlias.LIGHT]
+ * @property {Array} [geneVariations] */
+
 /**
  * Class representing alias visualized in a overlay.
  *
- * @param {number} javaObject.idObject
- * @param {number} [javaObject.value]
- * @param {{rgb:number}} [javaObject.color]
- * @param {number} javaObject.modelId
- * @param {string} [javaObject.description]
- * @param {number} [javaObject.uniqueId]
- * @param {string} [javaObject.type=LayoutAlias.LIGHT]
- * @param {Array} [javaObject.geneVariations]
- */
+ * @param {LayoutAliasOptions|LayoutAlias} javaObject
+ * @constructor
+ * */
 function LayoutAlias(javaObject) {
-  this.setId(javaObject.idObject);
-  this.setValue(javaObject.value);
-  this.setColor(javaObject.color);
-  this.setModelId(javaObject.modelId);
-  this.setDescription(javaObject.description);
-  this.setDataOverlayEntryId(javaObject.uniqueId);
-  if (javaObject.type === undefined) {
-    this.setType(LayoutAlias.LIGHT);
-  } else if (javaObject.type === LayoutAlias.GENETIC_VARIANT) {
-    if (javaObject.geneVariations !== undefined) {
-      this.setType(LayoutAlias.GENETIC_VARIANT);
-    } else {
-      this.setType(LayoutAlias.LIGHT);
+  if (javaObject instanceof LayoutAlias) {
+    this.setId(javaObject.getId());
+    this.setValue(javaObject.getValue());
+    this.setColor(javaObject.getColor());
+    this.setModelId(javaObject.getModelId());
+    this.setDescription(javaObject.getDescription());
+    this.setDataOverlayEntryId(javaObject.getDataOverlayEntryId());
+    this.setType(javaObject.getType());
+
+    this.setGeneVariants([]);
+    for (var i = 0; i < javaObject.getGeneVariants().length; i++) {
+      this.addGeneVariant(new GeneVariant(javaObject.getGeneVariants()[i]));
     }
-  } else if (javaObject.type === LayoutAlias.GENERIC) {
-    this.setType(LayoutAlias.GENERIC);
   } else {
-    throw new Error("Unknown type: " + javaObject.type);
-  }
+    this.setId(javaObject.idObject);
+    this.setValue(javaObject.value);
+    this.setColor(javaObject.color);
+    this.setModelId(javaObject.modelId);
+    this.setDescription(javaObject.description);
+    this.setDataOverlayEntryId(javaObject.uniqueId);
+    if (javaObject.type === undefined) {
+      this.setType(LayoutAlias.LIGHT);
+    } else if (javaObject.type === LayoutAlias.GENETIC_VARIANT) {
+      if (javaObject.geneVariations !== undefined) {
+        this.setType(LayoutAlias.GENETIC_VARIANT);
+      } else {
+        this.setType(LayoutAlias.LIGHT);
+      }
+    } else if (javaObject.type === LayoutAlias.GENERIC) {
+      this.setType(LayoutAlias.GENERIC);
+    } else {
+      throw new Error("Unknown type: " + javaObject.type);
+    }
 
-  this.setGeneVariants([]);
-  if (javaObject.geneVariations !== undefined) {
-    for (var i = 0; i < javaObject.geneVariations.length; i++) {
-      this.addGeneVariant(new GeneVariant(javaObject.geneVariations[i]));
+    this.setGeneVariants([]);
+    if (javaObject.geneVariations !== undefined) {
+      for (var j = 0; j < javaObject.geneVariations.length; j++) {
+        this.addGeneVariant(new GeneVariant(javaObject.geneVariations[j]));
+      }
     }
   }
 }
diff --git a/frontend-js/src/main/js/map/window/AliasInfoWindow.js b/frontend-js/src/main/js/map/window/AliasInfoWindow.js
index d14c5ac9a24ad4ff259eeb1f20c091f414f7490e..e4c874f0e8afbbabe90df5fab507cea46adeded9 100644
--- a/frontend-js/src/main/js/map/window/AliasInfoWindow.js
+++ b/frontend-js/src/main/js/map/window/AliasInfoWindow.js
@@ -450,7 +450,16 @@ AliasInfoWindow.prototype.createGenomicDiv = function (params) {
     promises = [];
     result.forEach(function (overlayEntries) {
       if (overlayEntries !== undefined) {
-        overlaysData = overlaysData.concat(overlayEntries);
+        //check if we have gene variants split into multiple groups
+        if (overlayEntries.length > 1 && overlayEntries[0].getType() === LayoutAlias.GENETIC_VARIANT) {
+          var tmpAlias = new LayoutAlias(overlayEntries[0]);
+          for (var i = 1; i < overlayEntries.length; i++) {
+            tmpAlias.setGeneVariants(tmpAlias.getGeneVariants().concat(overlayEntries[i].getGeneVariants()));
+            overlaysData.push(tmpAlias);
+          }
+        } else {
+          overlaysData = overlaysData.concat(overlayEntries);
+        }
       }
     });
     return Promise.all(promises);
diff --git a/model-command/.project b/model-command/.project
index 9dbb4bccdca54896776ec561b100cd19e5790deb..76db27f2b567de901675394f1adc139045b9abdf 100644
--- a/model-command/.project
+++ b/model-command/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (8).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/AddElementPrefixCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/AddElementPrefixCommand.java
index 752aa47d3532df9135ef1432d24381f69a0a8460..8184b8a700d4837f6579ec85cbe123899f4c00b5 100644
--- a/model-command/src/main/java/lcsb/mapviewer/commands/AddElementPrefixCommand.java
+++ b/model-command/src/main/java/lcsb/mapviewer/commands/AddElementPrefixCommand.java
@@ -1,6 +1,7 @@
 package lcsb.mapviewer.commands;
 
 import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.species.Element;
@@ -37,6 +38,9 @@ public class AddElementPrefixCommand extends ModelCommand {
       reaction.setIdReaction(prefix + reaction.getElementId());
       model.addReaction(reaction);
     }
+    for (Layer layer : model.getLayers()) {
+      layer.setLayerId(prefix + layer.getLayerId());
+    }
   }
 
 }
diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/MergeCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/MergeCommand.java
index e7a1e84e71672aa0e5f1dfc4aaa9eef385c5e11c..d40aaa69e4e148cee4879ed4b3cf1c6ad4bcb76e 100644
--- a/model-command/src/main/java/lcsb/mapviewer/commands/MergeCommand.java
+++ b/model-command/src/main/java/lcsb/mapviewer/commands/MergeCommand.java
@@ -40,6 +40,7 @@ public class MergeCommand extends NewModelCommand {
 
       result.addElements(model.getElements());
       result.addReactions(new ArrayList<>(model.getReactions()));
+      result.addLayers(model.getLayers());
 
       mapHeight = Math.max(mapHeight, offsetY + model.getHeight() + MARGIN);
       mapWidth = Math.max(mapWidth, offsetX + model.getWidth() + MARGIN);
diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/MoveCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/MoveCommand.java
index 96508b571b460834547b7758713085f34d499d27..e1755ce3db6240587209fff1558c03bdc4d1c764 100644
--- a/model-command/src/main/java/lcsb/mapviewer/commands/MoveCommand.java
+++ b/model-command/src/main/java/lcsb/mapviewer/commands/MoveCommand.java
@@ -3,6 +3,11 @@ package lcsb.mapviewer.commands;
 import java.awt.geom.Line2D;
 
 import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.graphics.PolylineData;
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
+import lcsb.mapviewer.model.map.layout.graphics.LayerOval;
+import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
+import lcsb.mapviewer.model.map.layout.graphics.LayerText;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.reaction.AbstractNode;
 import lcsb.mapviewer.model.map.reaction.Reaction;
@@ -24,6 +29,7 @@ public class MoveCommand extends ModelCommand {
    * Delta x.
    */
   private double dx;
+
   /**
    * Delta y.
    */
@@ -93,6 +99,27 @@ public class MoveCommand extends ModelCommand {
         reaction.getLine().setLine(i, line.getX1() + dx, line.getY1() + dy, line.getX2() + dx, line.getY2() + dy);
       }
     }
+
+    for (Layer layer : model.getLayers()) {
+      for (LayerText text : layer.getTexts()) {
+        text.setX(text.getX() + dx);
+        text.setY(text.getY() + dy);
+      }
+      for (LayerRect rect : layer.getRectangles()) {
+        rect.setX(rect.getX() + dx);
+        rect.setY(rect.getY() + dy);
+      }
+      for (LayerOval oval : layer.getOvals()) {
+        oval.setX(oval.getX() + dx);
+        oval.setY(oval.getY() + dy);
+      }
+      for (PolylineData line : layer.getLines()) {
+        for (int i = 0; i < line.getLines().size(); i++) {
+          Line2D l = line.getLines().get(i);
+          line.setLine(i, l.getX1() + dx, l.getY1() + dy, l.getX2() + dx, l.getY2() + dy);
+        }
+      }
+    }
   }
 
 }
diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java
index 5c8dba38badd517a8ecac322cf6ddf441faa6f86..d70b50c701fba73ee93b5da8e1721aa7672c7fc6 100644
--- a/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java
+++ b/model-command/src/main/java/lcsb/mapviewer/commands/SubModelCommand.java
@@ -54,7 +54,8 @@ public class SubModelCommand extends NewModelCommand {
    * @param polygon
    *          #polygon that limits the area for the new model
    */
-  public SubModelCommand(final Model model, final Path2D polygon, final Set<Integer> elementIds, final Set<Integer> reactionIds) {
+  public SubModelCommand(final Model model, final Path2D polygon, final Set<Integer> elementIds,
+      final Set<Integer> reactionIds) {
     super(model);
     this.polygon = polygon;
     this.elementIds = elementIds;
@@ -165,7 +166,7 @@ public class SubModelCommand extends NewModelCommand {
     for (final Layer layer : result.getLayers()) {
       List<LayerText> textToRemove = new ArrayList<>();
       for (final LayerText text : layer.getTexts()) {
-        if (!(polygon.intersects(text.getBorder()))) {
+        if (!(polygon.intersects(text.getBorder())) || elementIds.size() > 0 || reactionIds.size() > 0) {
           textToRemove.add(text);
         }
       }
diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/AddElementPrefixCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/AddElementPrefixCommandTest.java
index 9433ffaaaa1a5e7469cd7df18af12e12e2296a7d..e77efee4da9403c1f9826e585ebc7a85dd31de3d 100644
--- a/model-command/src/test/java/lcsb/mapviewer/commands/AddElementPrefixCommandTest.java
+++ b/model-command/src/test/java/lcsb/mapviewer/commands/AddElementPrefixCommandTest.java
@@ -1,9 +1,11 @@
 package lcsb.mapviewer.commands;
 
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 
 import org.junit.Test;
 
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
 import lcsb.mapviewer.model.map.model.Model;
 
 public class AddElementPrefixCommandTest extends CommandTestFunctions {
@@ -16,4 +18,14 @@ public class AddElementPrefixCommandTest extends CommandTestFunctions {
     assertNotNull(model.getElementByElementId("pre" + id));
   }
 
+  @Test
+  public void testPrefixLayer() throws CommandExecutionException {
+    Model model = super.createSimpleModel();
+    Layer layer = new Layer();
+    layer.setLayerId("x");
+    model.addLayer(layer);
+    new AddElementPrefixCommand(model, "pre").execute();
+    assertNotEquals("x", layer.getLayerId());
+  }
+
 }
diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/MoveCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/MoveCommandTest.java
index 309846d2bf93f1cd319b2003e2e769b00c83a9de..fa83087774b268ddeb184a9f4718fbe6425857ee 100644
--- a/model-command/src/test/java/lcsb/mapviewer/commands/MoveCommandTest.java
+++ b/model-command/src/test/java/lcsb/mapviewer/commands/MoveCommandTest.java
@@ -5,11 +5,16 @@ import static org.junit.Assert.assertTrue;
 
 import java.awt.geom.Line2D;
 import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 
 import org.junit.Test;
 
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.model.graphics.PolylineData;
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
+import lcsb.mapviewer.model.map.layout.graphics.LayerOval;
+import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
+import lcsb.mapviewer.model.map.layout.graphics.LayerText;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.reaction.Product;
 import lcsb.mapviewer.model.map.reaction.Reactant;
@@ -72,4 +77,66 @@ public class MoveCommandTest extends CommandTestFunctions {
     assertEquals(new Point2D.Double(50, 40), state.getPosition());
   }
 
+  @Test
+  public void testMoveLayerText() throws CommandExecutionException {
+    Model model = super.createSimpleModel();
+
+    Layer layer = new Layer();
+    LayerText text = new LayerText(new Rectangle2D.Double(10, 20, 30, 40), "xyz");
+    layer.addLayerText(text);
+    model.addLayer(layer);
+
+    new MoveCommand(model, 10, 20).execute();
+
+    assertEquals(20, text.getX(), Configuration.EPSILON);
+    assertEquals(40, text.getY(), Configuration.EPSILON);
+  }
+
+  @Test
+  public void testMoveLayerRect() throws CommandExecutionException {
+    Model model = super.createSimpleModel();
+
+    Layer layer = new Layer();
+    LayerRect rect = new LayerRect(new Rectangle2D.Double(10, 20, 30, 40));
+    layer.addLayerRect(rect);
+    model.addLayer(layer);
+
+    new MoveCommand(model, 10, 20).execute();
+
+    assertEquals(20, rect.getX(), Configuration.EPSILON);
+    assertEquals(40, rect.getY(), Configuration.EPSILON);
+  }
+
+  @Test
+  public void testMoveLayerOval() throws CommandExecutionException {
+    Model model = super.createSimpleModel();
+
+    Layer layer = new Layer();
+    LayerOval oval = new LayerOval();
+    oval.setX(10.0);
+    oval.setY(20.0);
+    layer.addLayerOval(oval);
+    model.addLayer(layer);
+
+    new MoveCommand(model, 10, 20).execute();
+
+    assertEquals(20, oval.getX(), Configuration.EPSILON);
+    assertEquals(40, oval.getY(), Configuration.EPSILON);
+  }
+
+  @Test
+  public void testMoveLayerLine() throws CommandExecutionException {
+    Model model = super.createSimpleModel();
+
+    Layer layer = new Layer();
+    PolylineData line = new PolylineData(new Point2D.Double(10, 20), new Point2D.Double(30, 40));
+    layer.addLayerLine(line);
+    model.addLayer(layer);
+
+    new MoveCommand(model, 10, 20).execute();
+
+    assertEquals(0, new Point2D.Double(20, 40).distance(line.getStartPoint()), Configuration.EPSILON);
+    assertEquals(0, new Point2D.Double(40, 60).distance(line.getEndPoint()), Configuration.EPSILON);
+  }
+
 }
diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java
index b96f428a94b66a7a1525cbf00a3b6d0fc056cb6f..4150cb89665bd91763b6489f68ed1b3ce1580e9b 100644
--- a/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java
+++ b/model-command/src/test/java/lcsb/mapviewer/commands/SubModelCommandTest.java
@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
 import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
 import java.util.Arrays;
 import java.util.HashSet;
 
@@ -11,6 +12,8 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
+import lcsb.mapviewer.model.map.layout.graphics.LayerText;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelComparator;
 
@@ -148,6 +151,31 @@ public class SubModelCommandTest extends CommandTestFunctions {
     assertEquals(0, copy.getReactions().size());
   }
 
+  @Test
+  public void testGetSubmodelWithElementIdsAndTextArea() throws Exception {
+    Model model = getModelForFile("testFiles/spliting_test_Case.xml", false);
+
+    Path2D polygon = new Path2D.Double();
+    polygon.moveTo(0, 0);
+    polygon.lineTo(0, 1000);
+    polygon.lineTo(1000, 1000);
+    polygon.lineTo(1000, 0);
+    polygon.closePath();
+    model.getElementByElementId("sa2").setId(-2);
+
+    Layer layer = new Layer();
+    LayerText text = new LayerText(new Rectangle2D.Double(10, 10, 20, 20), "xy");
+    layer.addLayerText(text);
+    model.addLayer(layer);
+
+    Model copy = new SubModelCommand(model, polygon, new HashSet<>(Arrays.asList(-2)), new HashSet<>()).execute();
+
+    assertEquals(1, copy.getElements().size());
+    assertEquals(0, copy.getReactions().size());
+    assertEquals(1, copy.getLayers().size());
+    assertEquals(0, copy.getLayers().iterator().next().getTexts().size());
+  }
+
   @Test
   public void testGetSubmodelWithEmptyElementIds() throws Exception {
     Model model = getModelForFile("testFiles/spliting_test_Case.xml", true);
diff --git a/model/.project b/model/.project
index aaaa0fce06cdb04fcc7a38db966e3d7a802e568f..44a99170d5a1d8c098ee5fc1f26b3028de600c4c 100644
--- a/model/.project
+++ b/model/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (2).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java b/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java
index 934187f82a623151ad14f9cb85a89152405f5b39..7690ea3d5d77a176034128ff729f8939a2e409e6 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java
@@ -3463,7 +3463,7 @@ public enum MiriamType {
       }, new Class<?>[] {}, "MIR:00000273",
       new Class<?>[] {},
       "massbank",
-      "PB000166"),
+      "MSBNK-IPB_Halle-PB000166"),
 
   MATHEMATICAL_MODELLING_ONTOLOGY("Mathematical Modelling Ontology",
       "http://bioportal.bioontology.org/ontologies/MAMO",
@@ -6670,8 +6670,8 @@ public enum MiriamType {
   private List<Class<? extends BioEntity>> validClass = new ArrayList<>();
 
   /**
-   * When class from this list is marked as "require at least one annotation"
-   * then annotation of this type is valid.
+   * When class from this list is marked as "require at least one annotation" then
+   * annotation of this type is valid.
    */
   private List<Class<? extends BioEntity>> requiredClass = new ArrayList<>();
 
@@ -6775,8 +6775,8 @@ public enum MiriamType {
    *          identifier in the format NAME:IDENTIFIER. Where NAME is the name
    *          from {@link MiriamType#commonName} and IDENTIFIER is resource
    *          identifier.
-   * @return {@link MiriamData} representing generalIdentifier, when identifier
-   *         is invalid InvalidArgumentException is thrown
+   * @return {@link MiriamData} representing generalIdentifier, when identifier is
+   *         invalid InvalidArgumentException is thrown
    */
   public static MiriamData getMiriamDataFromIdentifier(final String generalIdentifier) {
     int index = generalIdentifier.indexOf(":");
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/layout/graphics/LayerRect.java b/model/src/main/java/lcsb/mapviewer/model/map/layout/graphics/LayerRect.java
index 03619c01582a599651288c0933dd296fd9c9a545..0eeff2c1ee6062c55f2f075b384d4ca0138efc32 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/layout/graphics/LayerRect.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/layout/graphics/LayerRect.java
@@ -1,6 +1,7 @@
 package lcsb.mapviewer.model.map.layout.graphics;
 
 import java.awt.Color;
+import java.awt.geom.Rectangle2D;
 import java.io.Serializable;
 
 import javax.persistence.Column;
@@ -103,6 +104,13 @@ public class LayerRect implements Serializable, Drawable {
     height = layerRect.getHeight();
   }
 
+  public LayerRect(final Rectangle2D rect) {
+    x = rect.getX();
+    y = rect.getY();
+    width = rect.getWidth();
+    height = rect.getHeight();
+  }
+
   /**
    * Prepares a copy of the object.
    *
@@ -260,10 +268,12 @@ public class LayerRect implements Serializable, Drawable {
     return width * height;
   }
 
+  @Override
   public Color getBorderColor() {
     return borderColor;
   }
 
+  @Override
   public void setBorderColor(final Color borderColor) {
     this.borderColor = borderColor;
   }
diff --git a/pathvisio/.project b/pathvisio/.project
index 03de699bdd6e159ef0855b7312363a55bc669abf..d68188f8af21a94b27220f3577020e3b37604f87 100644
--- a/pathvisio/.project
+++ b/pathvisio/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder.launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelContructor.java b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelContructor.java
index be478b490aeed102e684fc2345a12ab06c8fdca0..c3262b837b30ab0a5bf13625e6d23103b9af4650 100644
--- a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelContructor.java
+++ b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/xml/ModelContructor.java
@@ -249,8 +249,8 @@ public class ModelContructor {
   }
 
   /**
-   * This function adds {@link Complex} to model from graph. ComplexName is set
-   * as groupId from GPML
+   * This function adds {@link Complex} to model from graph. ComplexName is set as
+   * groupId from GPML
    *
    * @param groups
    *          list of groups
@@ -303,6 +303,7 @@ public class ModelContructor {
    *          ...
    */
   protected void addElement(final Model model, final Graph graph, final Data data) {
+
     for (final DataNode dataNode : graph.getDataNodes()) {
       Species species = createSpecies(dataNode);
       species.addMiriamData(biopaxFactory.getMiriamData(graph.getBiopaxData(), dataNode.getBiopaxReferences()));
@@ -338,7 +339,7 @@ public class ModelContructor {
 
       } else {
         if (!shape.isCompartment()) {
-          if (shape.getShape().equals(GpmlShape.OVAL)) {
+          if (Objects.equals(shape.getShape(), GpmlShape.OVAL)) {
             LayerOval oval = createOval(shape);
             data.layer.addLayerOval(oval);
           } else if (shape.getComments().size() > 0 || shape.getTextLabel() != null) {
@@ -1242,8 +1243,7 @@ public class ModelContructor {
   }
 
   /**
-   * Tries to find a name to assign to complexes if complexes don't contain
-   * them.
+   * Tries to find a name to assign to complexes if complexes don't contain them.
    *
    * @param model
    *          model where complexes are placed
@@ -1314,8 +1314,8 @@ public class ModelContructor {
   }
 
   /**
-   * Tries to find a name to assign to compartments if compartments don't
-   * contain them.
+   * Tries to find a name to assign to compartments if compartments don't contain
+   * them.
    *
    * @param model
    *          model where compartments are placed
@@ -1365,8 +1365,8 @@ public class ModelContructor {
   }
 
   /**
-   * By default gpml doesn't offer information about compartments structure.
-   * This function fixes assignments to compartment and compartment aliases.
+   * By default gpml doesn't offer information about compartments structure. This
+   * function fixes assignments to compartment and compartment aliases.
    *
    * @param model
    *          model where assignments are fixed.
diff --git a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java
index 0bfed93e4100eece5dabb7ff96db13fdced30858..43314e18d3ba4dafcac70bbc99238b5f269a5a60 100644
--- a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java
+++ b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java
@@ -262,6 +262,13 @@ public class GPMLToModelTest extends WikipathwaysTestFunctions {
     assertEquals(0, getWarnings().size());
   }
 
+  @Test
+  public void testUnknownElementType() throws Exception {
+    String fileName = "testFiles/complex/unknown_element.gpml";
+    new GPMLToModel().getModel(fileName);
+    assertEquals(1, getWarnings().size());
+  }
+
   @Test
   public void testComplexName() throws Exception {
     String fileName = "testFiles/complex/complex_with_name.gpml";
diff --git a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/xml/ShapeParserTest.java b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/xml/ShapeParserTest.java
index 071e64f9b365872437751f3f23f2672f1260835c..10fb112f723a1497705d4bb7a5542e4b24aa255e 100644
--- a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/xml/ShapeParserTest.java
+++ b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/xml/ShapeParserTest.java
@@ -118,6 +118,15 @@ public class ShapeParserTest extends WikipathwaysTestFunctions {
     assertEquals(0, getWarnings().size());
   }
 
+  @Test
+  public void testParseUnknown() throws Exception {
+    Element node = fileToNode("testFiles/elements/unknown.xml");
+    Shape shape = parser.parse(node);
+    assertNotNull(shape);
+
+    assertEquals(1, getWarnings().size());
+  }
+
   @Test
   public void testParsePent() throws Exception {
     Element node = fileToNode("testFiles/elements/pent.xml");
diff --git a/pathvisio/testFiles/complex/unknown_element.gpml b/pathvisio/testFiles/complex/unknown_element.gpml
new file mode 100644
index 0000000000000000000000000000000000000000..57ea5983c95db00e73a9f2d565bc7d517f813177
--- /dev/null
+++ b/pathvisio/testFiles/complex/unknown_element.gpml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Pathway xmlns="http://pathvisio.org/GPML/2013a" Name="Insulin Signaling" Last-Modified="10/17/2013" Organism="Homo sapiens">
+  <Graphics BoardWidth="769.3333333333334" BoardHeight="710.0" />
+  <Shape TextLabel="eee" GraphId="c42d9">
+    <Comment>oval</Comment>
+    <BiopaxRef>d35</BiopaxRef>
+    <Graphics CenterX="668.25" CenterY="636.25" Width="353.5" Height="123.5" ZOrder="16384" FontSize="10" Valign="Middle" ShapeType="unknown-type" Rotation="0.0" />
+  </Shape>
+  <Biopax>
+  </Biopax>
+</Pathway>
+
diff --git a/pathvisio/testFiles/elements/unknown.xml b/pathvisio/testFiles/elements/unknown.xml
new file mode 100644
index 0000000000000000000000000000000000000000..04dfe4a9ec14beb3e9f424109943f3587d63630e
--- /dev/null
+++ b/pathvisio/testFiles/elements/unknown.xml
@@ -0,0 +1,5 @@
+  <Shape TextLabel="eee" GraphId="c42d9">
+    <Comment>oval</Comment>
+    <BiopaxRef>d35</BiopaxRef>
+    <Graphics CenterX="668.25" CenterY="636.25" Width="353.5" Height="123.5" ZOrder="16384" FontSize="10" Valign="Middle" ShapeType="unknown-type" Rotation="0.0" />
+  </Shape>
diff --git a/persist/.project b/persist/.project
index c76dcb2aefa82b83fd6ecb778b2001f2f790c783..6988b02d15c133024d99338879f5734516594fb0 100644
--- a/persist/.project
+++ b/persist/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (9).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/rest-api/.project b/rest-api/.project
index a4d854734795cb0c96fbba9960acd8b0cc90d759..fc78f7be58cd8140b065e18ab8de6a529224fa10 100644
--- a/rest-api/.project
+++ b/rest-api/.project
@@ -21,8 +21,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (10).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/convert/ConvertController.java b/rest-api/src/main/java/lcsb/mapviewer/api/convert/ConvertController.java
index 15b6edf1280b61f156199492d5f25378f1247c4d..606fd8ab2c38a3a7f200bb6b4359934893cb881c 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/convert/ConvertController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/convert/ConvertController.java
@@ -60,13 +60,19 @@ public class ConvertController extends BaseController {
     this.modelConverters = modelConverters;
   }
 
-  @PostMapping(value = "/{fromFormat}:{toFormat:.+}", produces = MediaType.APPLICATION_XML_VALUE)
+  @PostMapping(value = "/{fromFormat}:{toFormat:.+}",
+      consumes = {
+          MediaType.APPLICATION_XML_VALUE,
+          MediaType.APPLICATION_OCTET_STREAM_VALUE,
+          MediaType.TEXT_PLAIN_VALUE
+      },
+      produces = MediaType.APPLICATION_XML_VALUE)
   public byte[] convertInput(final @PathVariable(value = "fromFormat") String fromFormat,
       final @PathVariable(value = "toFormat") String toFormat,
-      final @RequestBody byte[] body)
-      throws IOException, QueryException, SBMLException,
+      final @RequestBody byte[] body) throws IOException, QueryException, SBMLException,
       InvalidInputDataExecption, InconsistentModelException, ConverterException {
-    ConverterParams params = createConvertParams(body);
+
+    ConverterParams params = new ConverterParams().inputStream(new ByteArrayInputStream(body));
     MinervaLoggerAppender appender = MinervaLoggerAppender.createAppender();
     Model original;
     try {
@@ -78,6 +84,8 @@ public class ConvertController extends BaseController {
         }
       }
       original.setNotes(notes.toString());
+    } catch (final InvalidInputDataExecption | ConverterException e) {
+      throw new QueryException("Problem with input file", e);
     } finally {
       MinervaLoggerAppender.unregisterLogEventStorage(appender);
     }
@@ -101,14 +109,19 @@ public class ConvertController extends BaseController {
     return model;
   }
 
-  @PostMapping(value = "/image/{fromFormat}:{toFormat:.+}")
+  @PostMapping(value = "/image/{fromFormat}:{toFormat:.+}",
+      consumes = {
+          MediaType.APPLICATION_XML_VALUE,
+          MediaType.APPLICATION_OCTET_STREAM_VALUE,
+          MediaType.TEXT_PLAIN_VALUE
+      })
   public @ResponseBody ResponseEntity<byte[]> convertInputToImage(
       final @PathVariable(value = "fromFormat") String fromFormat,
       final @PathVariable(value = "toFormat") String toFormat,
       final @RequestBody byte[] body) throws QueryException, IOException, DrawingException {
     Model original = null;
     try {
-      original = getModelParserByNameOrClass(fromFormat).createModel(createConvertParams(body));
+      original = getModelParserByNameOrClass(fromFormat).createModel(new ConverterParams().inputStream(new ByteArrayInputStream(body)));
     } catch (final InvalidInputDataExecption | ConverterException e) {
       throw new QueryException("Problem with input file", e);
     }
@@ -172,7 +185,11 @@ public class ConvertController extends BaseController {
 
   }
 
-  @PostMapping(value = "/merge/{fromFormat}:{toFormat}")
+  @PostMapping(value = "/merge/{fromFormat}:{toFormat}",
+      consumes = {
+          MediaType.APPLICATION_OCTET_STREAM_VALUE,
+          MediaType.TEXT_PLAIN_VALUE
+      })
   public @ResponseBody ResponseEntity<byte[]> mergeFilesToFile(
       final @PathVariable(value = "fromFormat") String fromFormat,
       final @PathVariable(value = "toFormat") String toFormat,
@@ -255,12 +272,6 @@ public class ConvertController extends BaseController {
     return result;
   }
 
-  private ConverterParams createConvertParams(final byte[] input) {
-    InputStream is = new ByteArrayInputStream(input);
-
-    return new ConverterParams().inputStream(is);
-  }
-
   private Converter getModelParserByNameOrClass(final String id) throws QueryException {
     try {
       return getModelParserByName(id);
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/files/FileController.java b/rest-api/src/main/java/lcsb/mapviewer/api/files/FileController.java
index 2791e86191abc4a43f2f776da083c7de121d4329..78c0261ca8c8b711c89e3a2de4d565362d11fa1e 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/files/FileController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/files/FileController.java
@@ -72,7 +72,7 @@ public class FileController extends BaseController {
   }
 
   @PreAuthorize("@fileService.getOwnerByFileId(#id)?.login == authentication.name")
-  @PostMapping(value = "/{id}:uploadContent")
+  @PostMapping(value = "/{id}:uploadContent", consumes = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
   public UploadedFileEntry uploadContent(final @PathVariable(value = "id") Integer id, final @RequestBody byte[] data)
       throws QueryException {
     UploadedFileEntry fileEntry = fileService.getById(id);
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/DirectoryNameGenerator.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/DirectoryNameGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..6945611975e77a3c3cceea97524720011fd012c0
--- /dev/null
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/DirectoryNameGenerator.java
@@ -0,0 +1,25 @@
+package lcsb.mapviewer.api.projects;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import lcsb.mapviewer.common.Md5;
+import lcsb.mapviewer.services.interfaces.IProjectService;
+
+@Service
+public class DirectoryNameGenerator implements IDirectoryNameGenerator {
+
+  private IProjectService projectService;
+
+  @Autowired
+  public DirectoryNameGenerator(final IProjectService projectService) {
+    this.projectService = projectService;
+  }
+
+  @Override
+  public String projectIdToDirectoryName(final String projectId) {
+    long id = projectService.getNextId();
+    return Md5.compute(projectId + "-" + id);
+  }
+
+}
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/IDirectoryNameGenerator.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/IDirectoryNameGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c9ef3a36ba74112bb41e331c899ecf21d1f49f1
--- /dev/null
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/IDirectoryNameGenerator.java
@@ -0,0 +1,6 @@
+package lcsb.mapviewer.api.projects;
+
+public interface IDirectoryNameGenerator {
+  String projectIdToDirectoryName(final String projectId);
+
+}
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
index 7070811b4698af462796af34be0f85649812f122..23fe21ddd8e4a9a100f32feeca2ea71db62437c3 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
@@ -56,7 +56,6 @@ import lcsb.mapviewer.annotation.services.annotators.AnnotatorException;
 import lcsb.mapviewer.api.BaseController;
 import lcsb.mapviewer.api.OperationNotAllowedException;
 import lcsb.mapviewer.api.minervanet.MinervaNetController;
-import lcsb.mapviewer.common.Md5;
 import lcsb.mapviewer.common.comparator.StringComparator;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.converter.Converter;
@@ -103,6 +102,7 @@ public class ProjectController extends BaseController {
   private ServletContext context;
   private MinervaNetController minervaNetController;
   private IProjectService projectService;
+  private IDirectoryNameGenerator directoryNameGenerator;
   private IConfigurationService configurationService;
   private IModelService modelService;
   private IElementService elementService;
@@ -116,10 +116,14 @@ public class ProjectController extends BaseController {
   private List<Converter> modelConverters;
 
   @Autowired
-  public ProjectController(final ServletContext context, final IUserService userService, final IProjectService projectService,
-      final IMeshService meshService, final List<Converter> modelConverters, final IFileService fileService, final IElementService elementService,
-      final IReactionService reactionService, final IModelService modelService, final IConfigurationService configurationService,
-      final IProjectBackgroundService projectBackgroundService, final MinervaNetController minervaNetController) {
+  public ProjectController(final ServletContext context, final IUserService userService,
+      final IProjectService projectService,
+      final IMeshService meshService, final List<Converter> modelConverters, final IFileService fileService,
+      final IElementService elementService,
+      final IReactionService reactionService, final IModelService modelService,
+      final IConfigurationService configurationService,
+      final IProjectBackgroundService projectBackgroundService, final MinervaNetController minervaNetController,
+      final IDirectoryNameGenerator directoryNameGenerator) {
     this.context = context;
     this.userService = userService;
     this.projectService = projectService;
@@ -132,6 +136,7 @@ public class ProjectController extends BaseController {
     this.configurationService = configurationService;
     this.projectBackgroundService = projectBackgroundService;
     this.minervaNetController = minervaNetController;
+    this.directoryNameGenerator = directoryNameGenerator;
   }
 
   @PreAuthorize("hasAnyAuthority('IS_ADMIN', 'READ_PROJECT:' + #projectId)")
@@ -533,7 +538,8 @@ public class ProjectController extends BaseController {
       final Authentication authentication,
       final @RequestParam Map<String, Object> body,
       final @Size(max = 255) @Pattern(regexp = "^[a-z0-9A-Z\\-_]+$",
-          message = "projectId can contain only alphanumeric characters and -_") @PathVariable(value = "projectId") String projectId)
+          message = "projectId can contain only alphanumeric characters and -_")
+      @PathVariable(value = "projectId") String projectId)
       throws IOException, QueryException, SecurityException {
     fixFormUrlEncodedBody(body);
     if (Objects.equals(body.get("zip-entries"), "")) {
@@ -642,8 +648,7 @@ public class ProjectController extends BaseController {
   }
 
   protected String computePathForProject(final String projectId, final String path) {
-    long id = projectService.getNextId();
-    return path + "/../map_images/" + Md5.compute(projectId + "-" + id) + "/";
+    return path + "/../map_images/" + directoryNameGenerator.projectIdToDirectoryName(projectId) + "/";
   }
 
   @PreAuthorize("hasAuthority('IS_ADMIN')"
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java
index 41c4aa8425ae438d297d08f8d7ea61c0c7a9a931..855237c155cb6fe578d49e75c2ef2eb8e2574046 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelController.java
@@ -75,7 +75,6 @@ import lcsb.mapviewer.model.map.InconsistentModelException;
 import lcsb.mapviewer.model.map.layout.ProjectBackground;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelData;
-import lcsb.mapviewer.model.overlay.DataOverlay;
 import lcsb.mapviewer.model.overlay.DataOverlayEntry;
 import lcsb.mapviewer.model.overlay.InvalidDataOverlayException;
 import lcsb.mapviewer.model.user.User;
@@ -440,9 +439,8 @@ public class ModelController extends BaseController {
 
     // Color with overlays
     for (final Integer overlayId : overlayIdsList) {
-      DataOverlay overlay = dataOverlayService.getDataOverlayById(projectId, overlayId);
+      Set<DataOverlayEntry> schemas = dataOverlayService.getDataOverlayEntriesById(projectId, overlayId);
 
-      Set<DataOverlayEntry> schemas = overlay.getEntries();
       new ColorModelCommand(part, schemas, userService.getColorExtractorForUser(user)).execute();
     }
 
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayEntryDTOSerializer.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayEntryDTOSerializer.java
index 0be25c64e64a9763e0b3d5d390d69adec39e3771..289b2067995b215fad89145fd6de8c265a0142e3 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayEntryDTOSerializer.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayEntryDTOSerializer.java
@@ -101,7 +101,8 @@ public class OverlayEntryDTOSerializer extends JsonSerializer<OverlayEntryDTO> {
         "description",
         "type",
         "geneVariations",
-        "uniqueId");
+        "uniqueId",
+        "width");
   }
 
   private void writeField(final JsonGenerator gen, final String field, final Object value, final PropertyFilter filter) throws IOException {
diff --git a/service/.project b/service/.project
index ec5afbcdc1c391a84415795af66de4941722f8d2..ba2b83aa611bce5c683cfb1ce886d97d3cf16200 100644
--- a/service/.project
+++ b/service/.project
@@ -16,8 +16,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (11).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/DataOverlayService.java b/service/src/main/java/lcsb/mapviewer/services/impl/DataOverlayService.java
index a0e639c28e176c772d6885c63329c0bed4010d68..e4475473940695c92f458d01ed6a106e37ab5eaf 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/DataOverlayService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/DataOverlayService.java
@@ -9,6 +9,7 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -261,13 +262,13 @@ public class DataOverlayService implements IDataOverlayService {
   }
 
   /**
-   * {@link DataOverlayEntry} sometimes contains merged value from few rows.
-   * This method split single {@link DataOverlayEntry} object to simple flat
-   * objects that can be serialized in a simple tab separated file.
+   * {@link DataOverlayEntry} sometimes contains merged value from few rows. This
+   * method split single {@link DataOverlayEntry} object to simple flat objects
+   * that can be serialized in a simple tab separated file.
    *
    * @param originalSchema
-   *          original {@link DataOverlayEntry} object that we want to split
-   *          into flat objects
+   *          original {@link DataOverlayEntry} object that we want to split into
+   *          flat objects
    * @return {@link List} of flat schema objects obtained from input
    */
   private List<DataOverlayEntry> splitColorSchema(final DataOverlayEntry originalSchema) {
@@ -372,8 +373,8 @@ public class DataOverlayService implements IDataOverlayService {
   }
 
   /**
-   * Returns String representing data of {@link GeneVariantDataOverlayEntry}
-   * that should appear in a given {@link ColorSchemaColumn}.
+   * Returns String representing data of {@link GeneVariantDataOverlayEntry} that
+   * should appear in a given {@link ColorSchemaColumn}.
    *
    * @param schema
    *          object for which data will be returned
@@ -592,4 +593,16 @@ public class DataOverlayService implements IDataOverlayService {
     }
   }
 
+  @Override
+  public Set<DataOverlayEntry> getDataOverlayEntriesById(final String projectId, final Integer overlayId) throws ObjectNotFoundException {
+    Set<DataOverlayEntry> result = getDataOverlayById(projectId, overlayId).getEntries();
+    Hibernate.initialize(result);
+    for (DataOverlayEntry dataOverlayEntry : result) {
+      Hibernate.initialize(dataOverlayEntry.getTypes());
+      Hibernate.initialize(dataOverlayEntry.getMiriamData());
+      Hibernate.initialize(dataOverlayEntry.getCompartments());
+    }
+    return result;
+  }
+
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java b/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java
index 91a30a5943b49df9a93843be26af0c6898c8edd2..ae10e42858fd9265a2de7409d31396cbe5304fda 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/PluginService.java
@@ -80,7 +80,7 @@ public class PluginService implements IPluginService {
 
   @Override
   public void update(final PluginDataEntry entry) {
-    pluginDataEntryDao.add(entry);
+    pluginDataEntryDao.update(entry);
   }
 
   @Override
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/PublicationService.java b/service/src/main/java/lcsb/mapviewer/services/impl/PublicationService.java
index a33c3b08f5ec40ae1f4c9be0b25781d6b41203ad..20d8f7a8938c0fe7c28ad99f8ee68a7bd29457ed 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/PublicationService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/PublicationService.java
@@ -41,7 +41,7 @@ public class PublicationService implements IPublicationService {
     for (final String id : missingIds) {
       try {
         Article article = pubmedParser.getPubmedArticleById(id);
-        if (article != null) {
+        if (article != null && id.equals(article.getPubmedId())) {
           articleDao.add(article);
         }
       } catch (final PubmedSearchException e) {
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IDataOverlayService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IDataOverlayService.java
index e1d7490320316be2235074ce268acdde49f9a419..1160199429516bb02dd0b7b4e67bfe6d7c56a895 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IDataOverlayService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IDataOverlayService.java
@@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 import lcsb.mapviewer.commands.ColorExtractor;
@@ -38,11 +39,11 @@ public interface IDataOverlayService {
     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.
+     * 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;
 
@@ -169,10 +170,11 @@ public interface IDataOverlayService {
 
   void waitForJobQueueToEmpty() throws InterruptedException, ExecutionException;
 
-
   void add(final DataOverlay overlay);
 
   FileEntry getDataOverlayFileById(final String projectId, final Integer overlayId) throws ObjectNotFoundException;
 
   byte[] generateLegend(String projectId, Integer overlayId, ColorExtractor colorExtractor) throws ObjectNotFoundException, IOException;
+
+  Set<DataOverlayEntry> getDataOverlayEntriesById(String projectId, Integer overlayId) throws ObjectNotFoundException;
 }
diff --git a/test_spelling.sh b/test_spelling.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5ecbd2f27d8c91b53a0860fb04ec99cc815d88f8
--- /dev/null
+++ b/test_spelling.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+result=0
+
+while read filename
+do
+  html=''
+  case $filename in  *.html)
+	  html=" --mode html ";;
+  esac
+  lines=`cat $filename | aspell $html --lang=en --encoding=utf-8 --add-extra-dicts=./.aspell.en.pws --add-extra-dicts=./.aspell-api-exceptions.pws list|wc -l`
+  if [ $lines -ne 0 ]
+  then
+    echo "[$filename] Unknown words:"
+    echo
+    cat $filename | aspell --lang=en $html --encoding=utf-8 --add-extra-dicts=./.aspell.en.pws --add-extra-dicts=./.aspell-api-exceptions.pws list |sort |uniq
+    result=1
+  fi
+done <<< "$(ls web/target/generated-docs/*.html CHANGELOG -c1)"
+
+exit $result
diff --git a/web/.project b/web/.project
index 0897627f36b8100d9a710728adbbec63f6411634..fc438eb8ab84b68d91263d67ef2b69ca18fed173 100644
--- a/web/.project
+++ b/web/.project
@@ -21,8 +21,13 @@
 			</arguments>
 		</buildCommand>
 		<buildCommand>
-			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<triggers>full,incremental,</triggers>
 			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/net.sf.eclipsecs.core.CheckstyleBuilder (13).launch</value>
+				</dictionary>
 			</arguments>
 		</buildCommand>
 		<buildCommand>
diff --git a/web/src/main/asciidoc/genomics.adoc b/web/src/main/asciidoc/genomics.adoc
index a265d559e15ffd583cf0d22c6cb456f6d76cf510..881c63c77c0c34fe162250ba15f7eb628fe68925 100644
--- a/web/src/main/asciidoc/genomics.adoc
+++ b/web/src/main/asciidoc/genomics.adoc
@@ -64,9 +64,6 @@ include::{snippets}/genomics/download_genome/curl-request.adoc[]
 === Request Parameters
 include::{snippets}/genomics/download_genome/request-parameters.adoc[]
 
-=== Response Fields
-include::{snippets}/genomics/download_genome/response-fields.adoc[]
-
 
 == Get information about specific downloaded genome
 === CURL sample
@@ -105,9 +102,6 @@ include::{snippets}/genomics/delete_genome_information/path-parameters.adoc[]
 === Path Parameters
 include::{snippets}/genomics/add_gene_mapping/path-parameters.adoc[]
 
-=== Response Fields
-include::{snippets}/genomics/add_gene_mapping/response-fields.adoc[]
-
 === CURL sample
 include::{snippets}/genomics/add_gene_mapping/curl-request.adoc[]
 
diff --git a/web/src/main/asciidoc/index.adoc b/web/src/main/asciidoc/index.adoc
index ee56886b186ef75271330782698c27730fdc48bb..b5eb4d5e4ed806a989e53d46b6d9c6a72781d830 100644
--- a/web/src/main/asciidoc/index.adoc
+++ b/web/src/main/asciidoc/index.adoc
@@ -17,7 +17,7 @@ For API calls that require authentication MINERVA_AUTH_TOKEN obtained during log
 == QuickStart guide
 Here is sample example that shows information about all projects accessible by guest account (anonymous user):
 
-include::{snippets}/projects/project_data/list/curl-request.adoc[]
+include::{snippets}/projects/project_data/list_guest/curl-request.adoc[]
 
 If we are interested in the API calls that require more privileges than anonymous user we need to login first:
 
diff --git a/web/src/test/java/lcsb/mapviewer/web/AllIntegrationTests.java b/web/src/test/java/lcsb/mapviewer/web/AllIntegrationTests.java
index dfbd94d4b23f3d1f3ce62107a145f40d0a98b734..b1f7095eddf13633e96c71d77e23f03a62169e54 100644
--- a/web/src/test/java/lcsb/mapviewer/web/AllIntegrationTests.java
+++ b/web/src/test/java/lcsb/mapviewer/web/AllIntegrationTests.java
@@ -9,6 +9,7 @@ import lcsb.mapviewer.web.bean.utils.StartupBeanTest;
 @RunWith(Suite.class)
 @SuiteClasses({ ConfigurationControllerIntegrationTest.class,
     ChemicalControllerIntegrationTest.class,
+    CommandFormatterTest.class,
     CommentControllerIntegrationTest.class,
     ConvertControllerIntegrationTest.class,
     DrugControllerIntegrationTest.class,
@@ -24,6 +25,7 @@ import lcsb.mapviewer.web.bean.utils.StartupBeanTest;
     ParameterControllerIntegrationTest.class,
     PluginControllerIntegrationTest.class,
     ProjectControllerIntegrationTest.class,
+    ProjectControllerIntegrationForDocsTest.class,
     PublicationsControllerIntegrationTest.class,
     ReactionControllerIntegrationTest.class,
     SpringSecurityGeneralIntegrationTest.class,
diff --git a/web/src/test/java/lcsb/mapviewer/web/CommandFormatterTest.java b/web/src/test/java/lcsb/mapviewer/web/CommandFormatterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c14fa665a8bc585d05401ac1903c7e859041ae0e
--- /dev/null
+++ b/web/src/test/java/lcsb/mapviewer/web/CommandFormatterTest.java
@@ -0,0 +1,46 @@
+package lcsb.mapviewer.web;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import lcsb.mapviewer.web.utils.CommandFormatterWithReplacingPostFilenameHeader;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+public class CommandFormatterTest extends ControllerIntegrationTest {
+
+  @Test
+  public void testExtractDefaultContentTypeContentType() throws Exception {
+    CommandFormatterWithReplacingPostFilenameHeader commandFormatter = new CommandFormatterWithReplacingPostFilenameHeader(" ");
+    String contentType = commandFormatter.getContentType(Arrays.asList(" "));
+    assertEquals(MediaType.APPLICATION_OCTET_STREAM_VALUE, contentType);
+  }
+
+  @Test
+  public void testExtractCustomContentType() throws Exception {
+    CommandFormatterWithReplacingPostFilenameHeader commandFormatter = new CommandFormatterWithReplacingPostFilenameHeader(" ");
+    String contentType = commandFormatter.getContentType(Arrays.asList(" ", "-H \"Content-Type: text/plain\""));
+    assertEquals("text/plain", contentType);
+  }
+
+  @Test
+  public void testExtractCustomContentTypeSingleQuote() throws Exception {
+    CommandFormatterWithReplacingPostFilenameHeader commandFormatter = new CommandFormatterWithReplacingPostFilenameHeader(" ");
+    String contentType = commandFormatter.getContentType(Arrays.asList(" ", "-H 'Content-Type: text/plain'"));
+    assertEquals("text/plain", contentType);
+  }
+
+  @Test
+  public void testExtractCustomContentTypeWithCharset() throws Exception {
+    CommandFormatterWithReplacingPostFilenameHeader commandFormatter = new CommandFormatterWithReplacingPostFilenameHeader(" ");
+    String contentType = commandFormatter.getContentType(Arrays.asList(" ", "-H 'Content-Type: text/html; charset=utf-8'"));
+    assertTrue(contentType.contains("charset=utf-8"));
+  }
+
+}
diff --git a/web/src/test/java/lcsb/mapviewer/web/CommentControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/CommentControllerIntegrationTest.java
index 176d3c651664de0a825f5f33372714d07b69cf24..9d28d3f46ea35c993a93ccc96482bf9c5286ff30 100644
--- a/web/src/test/java/lcsb/mapviewer/web/CommentControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/CommentControllerIntegrationTest.java
@@ -672,7 +672,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
@@ -717,7 +717,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
   public void testAddElementCommentAsAnonymous() throws Exception {
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
@@ -748,7 +748,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
@@ -789,7 +789,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
@@ -815,7 +815,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
@@ -844,7 +844,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
@@ -871,7 +871,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
@@ -892,7 +892,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
 
@@ -919,7 +919,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
 
@@ -941,7 +941,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("modelId", map.getId() + ""))));
 
@@ -1024,7 +1024,7 @@ public class CommentControllerIntegrationTest extends ControllerIntegrationTest
   private String createContentBody(final String type, final String value) throws IOException, UnsupportedEncodingException {
     List<BasicNameValuePair> params = new ArrayList<>(Arrays.asList(
         new BasicNameValuePair("email", "a@a.lu"),
-        new BasicNameValuePair("content", "tes content"),
+        new BasicNameValuePair("content", "test content"),
         new BasicNameValuePair("pinned", "true"),
         new BasicNameValuePair("coordinates", "10,2"),
         new BasicNameValuePair("modelId", map.getId() + "")));
diff --git a/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java
index 101b715b8e6e12e0eedb43382de6551c7092b32d..80b5ad1d833ffac55b91fd7ed2d6d9a9ffb93962 100644
--- a/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java
@@ -194,12 +194,12 @@ public abstract class ControllerIntegrationTest extends TestUtils {
   }
 
   /**
-   * This method can be used to work around the fact that MockMvc cannot
-   * retrieve cookies from Spring Security. The Reason for that is that MockMvc
-   * calls the controller directly and (partially?) bypasses Spring.
+   * This method can be used to work around the fact that MockMvc cannot retrieve
+   * cookies from Spring Security. The Reason for that is that MockMvc calls the
+   * controller directly and (partially?) bypasses Spring.
    * <p>
-   * This method creates a mocked session that can be used in a request as
-   * opposed to the token.
+   * This method creates a mocked session that can be used in a request as opposed
+   * to the token.
    * </p>
    * <p>
    * FIXME: Find a better solution, that does not violate the spirit of
@@ -366,13 +366,13 @@ public abstract class ControllerIntegrationTest extends TestUtils {
         + "</lambda></math>");
     map.addFunction(sbmlFunction);
 
-    SbmlParameter sbmlParameter = new SbmlParameter("param1");
-    sbmlParameter.setName("ppp");
+    SbmlParameter sbmlParameter = new SbmlParameter("parameter1");
+    sbmlParameter.setName("D coefficient");
     sbmlParameter.setValue(1.2);
     map.addParameter(sbmlParameter);
 
     SbmlUnit sbmlUnit = new SbmlUnit("u1");
-    sbmlUnit.setName("uuu");
+    sbmlUnit.setName("Weight");
     map.addUnit(sbmlUnit);
 
     Compartment comp = createCompartment();
@@ -382,6 +382,7 @@ public abstract class ControllerIntegrationTest extends TestUtils {
     reaction.setZ(2);
     reaction.setLine(new PolylineData(new Point2D.Double(0, 0), new Point2D.Double(10, 0)));
     reaction.addMiriamData(new MiriamData(MiriamType.PUBMED, "28725475"));
+    reaction.addMiriamData(new MiriamData(MiriamType.PUBMED, "123,"));
     SbmlKinetics kinetics = new SbmlKinetics();
     kinetics.setDefinition("<math xmlns=\"http://www.w3.org/1998/Math/MathML\"><lambda>\n"
         + "<bvar>\n"
@@ -444,7 +445,7 @@ public abstract class ControllerIntegrationTest extends TestUtils {
     ProjectBackground background = new ProjectBackground("Normal");
     int id = 0;
     for (final ModelData model : project.getModels()) {
-      ProjectBackgroundImageLayer layer = new ProjectBackgroundImageLayer(model, "dir_" + (id++));
+      ProjectBackgroundImageLayer layer = new ProjectBackgroundImageLayer(model, "directory_" + (id++));
       background.addProjectBackgroundImageLayer(layer);
     }
     background.setDefaultOverlay(true);
@@ -483,7 +484,8 @@ public abstract class ControllerIntegrationTest extends TestUtils {
     return element;
   }
 
-  private void assignCoordinates(final double x, final double y, final double width, final double height, final Element protein) {
+  private void assignCoordinates(final double x, final double y, final double width, final double height,
+      final Element protein) {
     protein.setX(x);
     protein.setY(y);
     protein.setZ(z++);
@@ -585,7 +587,8 @@ public abstract class ControllerIntegrationTest extends TestUtils {
     return createOverlay(project, admin, content, DataOverlayType.GENERIC);
   }
 
-  protected DataOverlay createOverlay(final Project project, final User admin, final String content, final DataOverlayType type)
+  protected DataOverlay createOverlay(final Project project, final User admin, final String content,
+      final DataOverlayType type)
       throws Exception {
     UploadedFileEntry file = new UploadedFileEntry();
     file.setFileContent(content.getBytes());
@@ -668,4 +671,9 @@ public abstract class ControllerIntegrationTest extends TestUtils {
             .description("target element that we are searching for in format TYPE:ID")
             .optional());
   }
+
+  protected PathParametersSnippet projectPathParameters() {
+    return pathParameters(parameterWithName("projectId").description("project identifier"));
+  }
+
 }
diff --git a/web/src/test/java/lcsb/mapviewer/web/ConvertControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/ConvertControllerIntegrationTest.java
index 0a703d35f65b0cd616f71542ab61bbbc1d508bf1..54618a6497af371dce41dffbded9462a6ba12181 100644
--- a/web/src/test/java/lcsb/mapviewer/web/ConvertControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/ConvertControllerIntegrationTest.java
@@ -11,17 +11,22 @@ import static org.springframework.restdocs.request.RequestDocumentation.paramete
 import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
+import java.awt.geom.Rectangle2D;
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 import org.apache.commons.io.FileUtils;
 import org.junit.Test;
@@ -38,7 +43,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 
 import lcsb.mapviewer.converter.ConverterParams;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
+import lcsb.mapviewer.model.map.layout.graphics.LayerText;
 import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
 import lcsb.mapviewer.model.map.species.Element;
 
 @RunWith(SpringJUnit4ClassRunner.class)
@@ -51,7 +59,7 @@ public class ConvertControllerIntegrationTest extends ControllerIntegrationTest
   public void testConvertInvalidFile() throws Exception {
     String body = "invalid content";
     RequestBuilder request = post("/api/convert/image/SBGN-ML:svg")
-        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .contentType(MediaType.TEXT_PLAIN_VALUE)
         .content(body);
 
     mockMvc.perform(request)
@@ -79,7 +87,7 @@ public class ConvertControllerIntegrationTest extends ControllerIntegrationTest
   public void testConvertInvalidMapFormat() throws Exception {
     String body = "invalid content";
     RequestBuilder request = post("/api/convert/image/unknown:svg")
-        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .contentType(MediaType.TEXT_PLAIN_VALUE)
         .content(body);
 
     mockMvc.perform(request)
@@ -155,8 +163,8 @@ public class ConvertControllerIntegrationTest extends ControllerIntegrationTest
     String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
     RequestBuilder request = post("/api/convert/{inputFormat}:{outputFormat}", "CellDesigner_SBML", "GPML")
         .header("post-filename", "input_file.xml")
-        .content(content.getBytes("UTF-8"))
-        .characterEncoding("UTF-8");
+        .contentType(MediaType.TEXT_PLAIN_VALUE)
+        .content(content);
 
     mockMvc.perform(request)
         .andDo(document("converter/format_conversion",
@@ -428,4 +436,89 @@ public class ConvertControllerIntegrationTest extends ControllerIntegrationTest
     assertTrue(inputs.size() > 0);
   }
 
+  @Test
+  public void testInvalidGpml2Sbml() throws Exception {
+    String content = "blah";
+
+    RequestBuilder request = post("/api/convert/{inputFormat}:{outputFormat}", "GPML", "SBML")
+        .header("post-filename", "input_file.xml")
+        .content(content.getBytes("UTF-8"))
+        .characterEncoding("UTF-8");
+    mockMvc.perform(request)
+        .andExpect(status().isBadRequest());
+  }
+
+  @Test
+  public void testInvalidGpml2Svg() throws Exception {
+    String content = "blah";
+
+    RequestBuilder request = post("/api/convert/image/{inputFormat}:{outputFormat}", "GPML", "svg")
+        .header("post-filename", "input_file.xml")
+        .content(content.getBytes("UTF-8"))
+        .characterEncoding("UTF-8");
+    mockMvc.perform(request)
+        .andExpect(status().isBadRequest());
+  }
+
+  @Test
+  public void convertCellDesignerToGpmlUsingUrlEncoded() throws Exception {
+    File file = new File("src/test/resources/convert/cd-sample.xml");
+    String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
+    content = URLEncoder.encode(content, "UTF-8");
+    RequestBuilder request = post("/api/convert/{inputFormat}:{outputFormat}", "CellDesigner_SBML", "GPML")
+        .header("post-filename", "input_file.xml")
+        .content(content.getBytes("UTF-8"))
+        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .characterEncoding("UTF-8");
+
+    mockMvc.perform(request)
+        .andExpect(status().isUnsupportedMediaType());
+  }
+
+  @Test
+  public void testMergeCellDesignerWithTextArea() throws Exception {
+    Model model = new ModelFullIndexed(null);
+    Layer layer = new Layer();
+    LayerText text = new LayerText(new Rectangle2D.Double(10, 20, 30, 40), "test text");
+    model.addLayer(layer);
+    layer.addLayerText(text);
+    model.setWidth(300);
+    model.setHeight(400);
+    CellDesignerXmlParser parser = new CellDesignerXmlParser();
+    String xml = parser.model2String(model);
+
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try (ZipOutputStream zos = new ZipOutputStream(baos)) {
+      ZipEntry entry = new ZipEntry("maps/map.xml");
+
+      zos.putNextEntry(entry);
+      zos.write(xml.getBytes());
+      zos.closeEntry();
+    } catch (IOException ioe) {
+      ioe.printStackTrace();
+    }
+
+    byte[] body = baos.toByteArray();
+    RequestBuilder request = post("/api/convert/merge/{inputFormat}:{outputFormat}", "CellDesigner_SBML",
+        "CellDesigner_SBML")
+            .header("post-filename", "maps.zip")
+            .content(body);
+
+    byte[] content = mockMvc.perform(request)
+        .andDo(document("converter/merge_maps",
+            pathParameters(
+                parameterWithName("inputFormat")
+                    .description("input format, available options: " + getModelInputConverters()),
+                parameterWithName("outputFormat")
+                    .description("output format, available options: " + getModelOutputConverters()))))
+        .andExpect(status().is2xxSuccessful())
+        .andReturn().getResponse().getContentAsByteArray();
+
+    Model outputMap = parser.createModel(new ConverterParams().inputStream(new ByteArrayInputStream(content)));
+
+    assertEquals(1, outputMap.getLayers().size());
+    assertEquals(1, outputMap.getLayers().iterator().next().getTexts().size());
+
+  }
+
 }
diff --git a/web/src/test/java/lcsb/mapviewer/web/EndPointsInputValidationTests.java b/web/src/test/java/lcsb/mapviewer/web/EndPointsInputValidationTests.java
index 984d0be04199d94527772cd05f9143fa79e6c0cd..8841c35648e60602da1304f4a7a178c8dbf8ebc2 100644
--- a/web/src/test/java/lcsb/mapviewer/web/EndPointsInputValidationTests.java
+++ b/web/src/test/java/lcsb/mapviewer/web/EndPointsInputValidationTests.java
@@ -43,7 +43,7 @@ public class EndPointsInputValidationTests extends ControllerIntegrationTest {
 
   private static String[] testValues = { " ", "-1", "0", "empty", "admin", "1.00,2.00", "17.00", "1" };
   private static List<HttpStatus> validResponses = Arrays.asList(HttpStatus.OK, HttpStatus.BAD_REQUEST,
-      HttpStatus.NOT_FOUND, HttpStatus.FORBIDDEN, HttpStatus.UNAVAILABLE_FOR_LEGAL_REASONS);
+      HttpStatus.NOT_FOUND, HttpStatus.FORBIDDEN, HttpStatus.UNAVAILABLE_FOR_LEGAL_REASONS, HttpStatus.UNSUPPORTED_MEDIA_TYPE);
   @Autowired
   private RequestMappingHandlerMapping requestMappingHandlerMapping;
 
diff --git a/web/src/test/java/lcsb/mapviewer/web/FileControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/FileControllerIntegrationTest.java
index b139f65f101f4fc47f317fc078c8ab9bc22c87cf..fd8e1413177da84c515d7f0873db1ac123b611a2 100644
--- a/web/src/test/java/lcsb/mapviewer/web/FileControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/FileControllerIntegrationTest.java
@@ -83,12 +83,11 @@ public class FileControllerIntegrationTest extends ControllerIntegrationTest {
         .get("id")
         .getAsString();
 
-    body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
-
-        new BasicNameValuePair("data", "test_content"))));
+    body = "test_content\nhello world";
 
     request = post("/api/files/{fileId}:uploadContent", fileId)
-        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE)
+        .header("post-filename", "input_file.txt")
         .content(body)
         .session(session);
 
@@ -96,13 +95,13 @@ public class FileControllerIntegrationTest extends ControllerIntegrationTest {
         .andDo(document("file/upload_content",
             pathParameters(parameterWithName("fileId")
                 .description("file id")),
-            requestParameters(
-                parameterWithName("data")
-                    .description("content to append")),
+            requestParameters(),
             responseFields(fileResponseFields())))
         .andExpect(status().is2xxSuccessful());
 
-    assertNotNull(fileService.getById(Integer.valueOf(fileId)));
+    UploadedFileEntry file = fileService.getById(Integer.valueOf(fileId));
+    assertNotNull(file);
+    assertEquals(body, new String(file.getFileContent()));
   }
 
   @Test
diff --git a/web/src/test/java/lcsb/mapviewer/web/GenomicsControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/GenomicsControllerIntegrationTest.java
index 43717a34696934599e98e81e7075d60dff0198ad..5d985272ab110d6f585e5538e513ad46ed0780e6 100644
--- a/web/src/test/java/lcsb/mapviewer/web/GenomicsControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/GenomicsControllerIntegrationTest.java
@@ -75,7 +75,8 @@ public class GenomicsControllerIntegrationTest extends ControllerIntegrationTest
   @After
   public void tearDown() throws Exception {
     referenceGenomeConnector.waitForDownloadsToFinish();
-    ReferenceGenome referenceGenome = referenceGenomeService.getReferenceGenomeViewByParams(ebolaId, ReferenceGenomeType.UCSC, "eboVir3");
+    ReferenceGenome referenceGenome = referenceGenomeService.getReferenceGenomeViewByParams(ebolaId,
+        ReferenceGenomeType.UCSC, "eboVir3");
     if (referenceGenome != null) {
       referenceGenomeService.removeGenome(referenceGenome);
     }
@@ -212,7 +213,8 @@ public class GenomicsControllerIntegrationTest extends ControllerIntegrationTest
         .andDo(document("genomics/download_genome",
             requestParameters(
                 parameterWithName("organismId").description("organism taxonomy id"),
-                parameterWithName("type").description("genome type, acceptable values: " + snippets.getOptionsAsString(ReferenceGenomeType.class)),
+                parameterWithName("type").description(
+                    "genome type, acceptable values: " + snippets.getOptionsAsString(ReferenceGenomeType.class)),
                 parameterWithName("version").description("genome version"),
                 parameterWithName("url").description("url address from where the file should be downloaded")),
             responseFields()))
@@ -243,7 +245,7 @@ public class GenomicsControllerIntegrationTest extends ControllerIntegrationTest
     genome.setType(ReferenceGenomeType.UCSC);
     genome.setVersion("eboVir3");
     ReferenceGenomeGeneMapping mapping = new ReferenceGenomeGeneMapping();
-    mapping.setName("xy");
+    mapping.setName("custom-gene-mapping");
     mapping.setSourceUrl("https://minerva-dev.lcsb.uni.lu/tmp/refGene.bb");
     genome.addReferenceGenomeGeneMapping(mapping);
 
@@ -307,7 +309,8 @@ public class GenomicsControllerIntegrationTest extends ControllerIntegrationTest
             .description("download progress")
             .type(JsonFieldType.NUMBER),
         fieldWithPath("geneMapping[].idObject")
-            .ignored(),
+            .description("id of the gene mapping")
+            .type(JsonFieldType.NUMBER),
         fieldWithPath("idObject")
             .description("unique id of genome in minerva")
             .type(JsonFieldType.NUMBER),
@@ -352,7 +355,8 @@ public class GenomicsControllerIntegrationTest extends ControllerIntegrationTest
     mockMvc.perform(request)
         .andDo(document("genomics/delete_genome_information",
             pathParameters(
-                parameterWithName("genomeId").description("genome id")),
+                parameterWithName("genomeId")
+                    .description("genome id (genomeId is retrieved as idObject described above in 6.3)")),
             responseFields()))
         .andExpect(status().is2xxSuccessful());
 
@@ -398,7 +402,7 @@ public class GenomicsControllerIntegrationTest extends ControllerIntegrationTest
     mockMvc.perform(request)
         .andDo(document("genomics/add_gene_mapping",
             pathParameters(
-                parameterWithName("genomeId").description("genome id")),
+                parameterWithName("genomeId").description("genome id (genomeId is retrieved as idObject described above in 6.3)")),
             requestParameters(parameterWithName("name").description("name of the gene-genome mapping"),
                 parameterWithName("url").description("url where file with mapping is located")),
             responseFields()))
@@ -425,8 +429,10 @@ public class GenomicsControllerIntegrationTest extends ControllerIntegrationTest
     mockMvc.perform(request)
         .andDo(document("genomics/delete_gene_mapping",
             pathParameters(
-                parameterWithName("genomeId").description("genome id"),
-                parameterWithName("geneMappingId").description("gene genome mapping id"))))
+                parameterWithName("genomeId")
+                    .description("genome id (genomeId is retrieved as idObject described above in 6.3)"),
+                parameterWithName("geneMappingId")
+                    .description("gene genome mapping id (geneMapping[].objectId described in 6.3)"))))
         .andExpect(status().is2xxSuccessful());
   }
 
diff --git a/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java
index a6badf6ddfb46196510448c7aa38b164bf80e572..998f231085c328b53b77ca4b6358f50359313ed4 100644
--- a/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/MapControllerIntegrationTest.java
@@ -218,7 +218,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest {
             .type("int")
             .optional(),
         subsectionWithPath("[].other")
-            .description("list of oher properties")
+            .description("list of other properties")
             .type("object")
             .optional());
   }
@@ -282,7 +282,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest {
             .type(JsonFieldType.OBJECT)
             .optional(),
         subsectionWithPath("[].other")
-            .description("list of oher properties")
+            .description("list of other properties")
             .type(JsonFieldType.OBJECT)
             .optional()));
     fields.addAll(reactionNodeFields("[].reactants[]"));
@@ -636,7 +636,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest {
             mapPathParameters(),
             responseFields(
                 fieldWithPath("[]")
-                    .description("list of all full search queries that could be used for quering the map")
+                    .description("list of all full search queries that could be used for querying the map")
                     .type("array<string>"))))
         .andExpect(status().is2xxSuccessful());
   }
@@ -655,7 +655,7 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest {
             .type("number"),
         fieldWithPath("defaultZoomLevel").description("default zoom level used in frontend visualization")
             .type("number"),
-        fieldWithPath("minZoom").description("minimum zoom level availbale for the map").type("number"),
+        fieldWithPath("minZoom").description("minimum zoom level available for the map").type("number"),
         fieldWithPath("maxZoom").description("maximum zoom level available for the map").type("number"),
         fieldWithPath("authors").description("list of authors").type("array<Author>"),
         fieldWithPath("references").description("list of references").type("array<Reference>"),
@@ -856,6 +856,25 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest {
         .andExpect(status().is2xxSuccessful());
   }
 
+  @Test
+  public void testDownloadModelWithOverlay() throws Exception {
+    MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD);
+
+    ModelData submap = getSubmap();
+    User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
+    DataOverlay overlay = createOverlay(project, admin, "name\tvalue\nGSTA4\t1");
+
+    RequestBuilder request = get("/api/projects/{projectId}/models/{mapId}:downloadModel?"
+        + "handlerClass={handlerClass}"
+        + "&overlayIds={overlayId}", TEST_PROJECT, submap.getId(),
+        CellDesignerXmlParser.class.getCanonicalName(),
+        overlay.getId())
+            .session(session);
+
+    mockMvc.perform(request)
+        .andExpect(status().is2xxSuccessful());
+  }
+
   @Test
   public void testDownloadSubmapModelWithPost() throws Exception {
     ModelData submap = getSubmap();
diff --git a/web/src/test/java/lcsb/mapviewer/web/MiRnaControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/MiRnaControllerIntegrationTest.java
index fd595ba6dd62f5c3b742524407831e74888b33f9..18eed126aa33a26842516925e1325146926d57e0 100644
--- a/web/src/test/java/lcsb/mapviewer/web/MiRnaControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/MiRnaControllerIntegrationTest.java
@@ -18,7 +18,6 @@ import org.springframework.test.web.servlet.RequestBuilder;
 @RunWith(SpringJUnit4ClassRunner.class)
 public class MiRnaControllerIntegrationTest extends ControllerIntegrationTest {
 
-
   @Before
   public void setup() {
   }
@@ -72,7 +71,7 @@ public class MiRnaControllerIntegrationTest extends ControllerIntegrationTest {
             getProjectPathParameters(),
             responseFields(
                 fieldWithPath("[]")
-                    .description("list of suggested mirna queries")
+                    .description("list of suggested miRNA queries")
                     .type("array<string>"))))
         .andExpect(status().is2xxSuccessful())
         .andReturn().getResponse().getContentAsString();
@@ -92,7 +91,7 @@ public class MiRnaControllerIntegrationTest extends ControllerIntegrationTest {
   private ResponseFieldsSnippet listOfMiRnaFields() {
     return responseFields(
         subsectionWithPath("[].id")
-            .description("identifier of the mirna")
+            .description("identifier of the miRNA")
             .type("object"),
         fieldWithPath("[].name")
             .description("name")
diff --git a/web/src/test/java/lcsb/mapviewer/web/NumericDirectoryNameGeneratorConfiguration.java b/web/src/test/java/lcsb/mapviewer/web/NumericDirectoryNameGeneratorConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4894f40e1c52c9dac01be122eae7b54dc8aa528
--- /dev/null
+++ b/web/src/test/java/lcsb/mapviewer/web/NumericDirectoryNameGeneratorConfiguration.java
@@ -0,0 +1,34 @@
+package lcsb.mapviewer.web;
+
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Profile;
+
+import lcsb.mapviewer.api.projects.IDirectoryNameGenerator;
+import lcsb.mapviewer.common.Md5;
+import lcsb.mapviewer.services.interfaces.IProjectService;
+
+@Profile("NumericDirectoryNameGeneratorProfile")
+@Configuration
+public class NumericDirectoryNameGeneratorConfiguration {
+
+  @Autowired
+  private IProjectService projectService;
+
+  @Bean
+  @Primary
+  public IDirectoryNameGenerator directoryNameGenerator() throws Exception {
+    IDirectoryNameGenerator mock = Mockito.mock(IDirectoryNameGenerator.class);
+
+    Mockito.when(mock.projectIdToDirectoryName(Mockito.anyString())).thenAnswer(projectId -> {
+      long id = projectService.getNextId();
+      return Md5.compute(projectId + "-" + id).replaceAll("[a-z]", "0");
+    });
+
+    return mock;
+  }
+
+}
diff --git a/web/src/test/java/lcsb/mapviewer/web/OverlayControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/OverlayControllerIntegrationTest.java
index 1ee23b297ffd747577db30fe3b22729f8e200237..e261c654fea3ece0f237683ec215caef4efa13b9 100644
--- a/web/src/test/java/lcsb/mapviewer/web/OverlayControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/OverlayControllerIntegrationTest.java
@@ -437,6 +437,28 @@ public class OverlayControllerIntegrationTest extends ControllerIntegrationTest
         .andReturn().getResponse().getContentAsString();
   }
 
+  @Test
+  public void testGetReactionForOverlayWithWidth() throws Exception {
+    String reactionId = reaction.getElementId();
+    DataOverlay overlay = createOverlay(project, user, "element_identifier\tvalue\tline_width\n" + reactionId + "\t1\t6");
+
+    MockHttpSession session = createSession(TEST_USER_LOGIN, TEST_USER_PASSWORD);
+
+    RequestBuilder request = get(
+        "/api/projects/{projectId}/overlays/{overlayId}/models/{mapId}/bioEntities/reactions/{reactionId}/",
+        TEST_PROJECT, overlay.getId(), map.getId(), reaction.getId())
+            .session(session);
+
+    String json = mockMvc.perform(request)
+        .andExpect(status().is2xxSuccessful())
+        .andReturn().getResponse().getContentAsString();
+    List<Map<String, Object>> objects = objectMapper.readValue(json, new TypeReference<List<Map<String, Object>>>() {
+    });
+    Map<?, ?> content = (Map<?, ?>) objects.get(0).get("overlayContent");
+    assertTrue(content.containsKey("width"));
+
+  }
+
   private PathParametersSnippet getOverlayReactionPathParameters() {
     return getOverlayMapPathParameters().and(parameterWithName("reactionId").description("reaction identifier"));
   }
@@ -578,10 +600,11 @@ public class OverlayControllerIntegrationTest extends ControllerIntegrationTest
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("content", "element_identifier\tvalue\n\t-1"),
         new BasicNameValuePair("name", "overlay name"),
-        new BasicNameValuePair("description", "overlay name"),
-        new BasicNameValuePair("filename", "overlay name"),
+        new BasicNameValuePair("description", "overlay description"),
+        new BasicNameValuePair("filename", "source.txt"),
         new BasicNameValuePair("googleLicenseConsent", "false"),
         new BasicNameValuePair("type", "GENERIC"))));
+    logger.debug(body);
 
     RequestBuilder request = post("/api/projects/{projectId}/overlays/", TEST_PROJECT)
         .contentType(MediaType.APPLICATION_FORM_URLENCODED)
@@ -1333,7 +1356,7 @@ public class OverlayControllerIntegrationTest extends ControllerIntegrationTest
             .description("identifier")
             .type(JsonFieldType.NUMBER),
         fieldWithPath("publicOverlay")
-            .description("is the data overlay publicaly available to all users")
+            .description("is the data overlay publicly available to all users")
             .type(JsonFieldType.BOOLEAN),
         fieldWithPath("googleLicenseConsent")
             .description("did creator accepted license required by Google Maps API")
diff --git a/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java
index b1f45c22adc1a7c46d839d32416498fa5cdf1dbc..1f5352d5813971b05bea3183aab1ed13115d8907 100644
--- a/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/PluginControllerIntegrationTest.java
@@ -132,7 +132,7 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
                     .description("version"),
                 parameterWithName("isDefault")
                     .optional()
-                    .description("should be opened automatically whem map is browsed"),
+                    .description("should be opened automatically when map is browsed"),
                 parameterWithName("isPublic")
                     .description("should the plugin be visible by all users"),
                 parameterWithName("url")
@@ -171,7 +171,7 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
         .description("md5 checksum of the source file")
         .type("string"),
         fieldWithPath("isDefault")
-            .description("should be opened automatically whem map is browsed")
+            .description("should be opened automatically when map is browsed")
             .type("boolean"),
         fieldWithPath("isPublic")
             .description("should be visible on plugin list to all users")
@@ -325,6 +325,46 @@ public class PluginControllerIntegrationTest extends ControllerIntegrationTest {
     assertEquals("xxx", result);
   }
 
+  @Test
+  public void updateUserPluginData() throws Exception {
+    MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_LOGIN);
+
+    String body = "value=xxx";
+    Plugin plugin = createPlugin();
+
+    RequestBuilder request = post("/api/plugins/{hash}/data/users/{key}/", plugin.getHash(), "my_key")
+        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .session(session)
+        .content(body);
+
+    mockMvc.perform(request)
+        .andExpect(status().is2xxSuccessful());
+
+    body = "value=xxx2";
+    request = post("/api/plugins/{hash}/data/users/{key}/", plugin.getHash(), "my_key")
+        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .session(session)
+        .content(body);
+
+    mockMvc.perform(request)
+        .andExpect(status().is2xxSuccessful());
+
+    request = get("/api/plugins/{hash}/data/users/{key}/", plugin.getHash(), "my_key")
+        .session(session);
+
+    String response = mockMvc.perform(request)
+        .andExpect(status().is2xxSuccessful())
+        .andReturn().getResponse().getContentAsString();
+
+    String result = new JsonParser()
+        .parse(response)
+        .getAsJsonObject()
+        .get("value")
+        .getAsString();
+
+    assertEquals("xxx2", result);
+  }
+
   @Test
   public void removeGlobalPluginData() throws Exception {
     Plugin plugin = createPlugin();
diff --git a/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationForDocsTest.java b/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationForDocsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac5f1eeccedcb7efa59ca1776c7849e22e870922
--- /dev/null
+++ b/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationForDocsTest.java
@@ -0,0 +1,262 @@
+package lcsb.mapviewer.web;
+
+import static org.junit.Assert.assertEquals;
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
+import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
+import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
+import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.restdocs.request.ParameterDescriptor;
+import org.springframework.restdocs.request.RequestParametersSnippet;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.web.servlet.RequestBuilder;
+
+import lcsb.mapviewer.converter.zip.ZipEntryFileDeserializer;
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.ProjectStatus;
+import lcsb.mapviewer.model.cache.UploadedFileEntry;
+import lcsb.mapviewer.model.graphics.MapCanvasType;
+import lcsb.mapviewer.model.map.model.SubmodelType;
+import lcsb.mapviewer.model.user.ConfigurationElementType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.services.interfaces.IConfigurationService;
+import lcsb.mapviewer.services.interfaces.IProjectService;
+import lcsb.mapviewer.services.interfaces.IUserService;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ActiveProfiles("NumericDirectoryNameGeneratorProfile")
+public class ProjectControllerIntegrationForDocsTest extends ControllerIntegrationTest {
+
+  private static final String CURATOR_PASSWORD = "curator_pass";
+  private static final String CURATOR_LOGIN = "curator_user";
+
+  @Autowired
+  private IUserService userService;
+
+  @Autowired
+  private IProjectService projectService;
+
+  @Autowired
+  private ProjectSnippets snippets;
+
+  private User curator;
+
+  @Autowired
+  private IConfigurationService configurationService;
+
+  @Before
+  public void setup() {
+    curator = createCurator(CURATOR_LOGIN, CURATOR_PASSWORD);
+    configurationService.setConfigurationValue(ConfigurationElementType.MINERVA_ROOT, "https://pdmap.uni.lu/minerva/");
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    removeProject(TEST_PROJECT);
+    removeUser(curator);
+    configurationService.setConfigurationValue(ConfigurationElementType.MINERVA_ROOT, "");
+  }
+
+  @Test
+  public void addComplexProjectAsCurator() throws Exception {
+    User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
+    try {
+      UploadedFileEntry fileEntry = createFile(
+          Files.readAllBytes(Paths.get("./src/test/resources/complex_model_with_submaps.zip")), admin);
+
+      String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
+          new BasicNameValuePair("projectId", TEST_PROJECT),
+          new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
+          new BasicNameValuePair("name", "Project name"),
+          new BasicNameValuePair("version", "0.0.1"),
+          new BasicNameValuePair("notify-email", "minerva@uni.lu"),
+          new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
+          new BasicNameValuePair("parser",
+              "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"),
+
+          new BasicNameValuePair("zip-entries[0][_type]", "MAP"),
+          new BasicNameValuePair("zip-entries[0][_filename]", "main.xml"),
+          new BasicNameValuePair("zip-entries[0][_data][root]", "true"),
+          new BasicNameValuePair("zip-entries[0][_data][name]", "main"),
+          new BasicNameValuePair("zip-entries[0][_data][type][id]", "UNKNOWN"),
+
+          new BasicNameValuePair("zip-entries[1][_type]", "MAP"),
+          new BasicNameValuePair("zip-entries[1][_filename]", "submaps/mapping.xml"),
+          new BasicNameValuePair("zip-entries[1][_data][root]", "false"),
+          new BasicNameValuePair("zip-entries[1][_data][name]", "mapping"),
+          new BasicNameValuePair("zip-entries[1][_data][type][id]", "UNKNOWN"),
+
+          new BasicNameValuePair("zip-entries[2][_type]", "MAP"),
+          new BasicNameValuePair("zip-entries[2][_filename]", "submaps/s1.xml"),
+          new BasicNameValuePair("zip-entries[2][_data][root]", "false"),
+          new BasicNameValuePair("zip-entries[2][_data][name]", "s1"),
+          new BasicNameValuePair("zip-entries[2][_data][type][id]", "UNKNOWN"),
+
+          new BasicNameValuePair("zip-entries[3][_type]", "MAP"),
+          new BasicNameValuePair("zip-entries[3][_filename]", "submaps/s2.xml"),
+          new BasicNameValuePair("zip-entries[3][_data][root]", "false"),
+          new BasicNameValuePair("zip-entries[3][_data][name]", "s2"),
+          new BasicNameValuePair("zip-entries[3][_data][type][id]", "UNKNOWN"),
+
+          new BasicNameValuePair("zip-entries[4][_type]", "MAP"),
+          new BasicNameValuePair("zip-entries[4][_filename]", "submaps/s3.xml"),
+          new BasicNameValuePair("zip-entries[4][_data][root]", "false"),
+          new BasicNameValuePair("zip-entries[4][_data][name]", "s3"),
+          new BasicNameValuePair("zip-entries[4][_data][type][id]", "UNKNOWN")
+
+      )));
+
+      RequestBuilder request = post("/api/projects/{projectId}/", TEST_PROJECT)
+          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+          .content(body)
+          .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
+
+      mockMvc.perform(request).andExpect(status().is2xxSuccessful())
+          .andDo(document("projects/project_data/create_zip",
+              projectPathParameters(),
+              createProjectRequestSnippet(),
+
+              snippets.getProjectSnippet()));
+
+    } finally {
+      waitForProjectToFinishLoading(TEST_PROJECT);
+      Project project = projectService.getProjectByProjectId(TEST_PROJECT);
+      assertEquals(ProjectStatus.DONE, project.getStatus());
+    }
+  }
+
+  @Test
+  public void addProjectAsCurator() throws Exception {
+    User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
+    try {
+      UploadedFileEntry fileEntry = createFile(
+          new String(Files.readAllBytes(Paths.get("./src/test/resources/generic.xml")), "UTF-8"),
+          admin);
+
+      String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
+          new BasicNameValuePair("projectId", TEST_PROJECT),
+          new BasicNameValuePair("name", "New Disease Map"),
+          new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
+          new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
+          new BasicNameValuePair("cache", "false"),
+          new BasicNameValuePair("description", "this is my awesome project"),
+          new BasicNameValuePair("notify-email", "notify.me@uni.lu"),
+          new BasicNameValuePair("disease", "D010300"),
+          new BasicNameValuePair("organism", "9606"),
+          new BasicNameValuePair("sbgn", "false"),
+          new BasicNameValuePair("version", "0.0.1"),
+          new BasicNameValuePair("annotate", "false"),
+          new BasicNameValuePair("verify-annotations", "false"),
+          new BasicNameValuePair("parser", "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"))));
+
+      RequestBuilder request = post("/api/projects/{projectId}/", TEST_PROJECT)
+          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+          .content(body)
+          .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
+
+      mockMvc.perform(request).andExpect(status().is2xxSuccessful())
+          .andDo(document("projects/project_data/create_simple",
+              projectPathParameters(),
+              createProjectRequestSnippet(),
+              snippets.getProjectSnippet()));
+
+    } finally {
+      waitForProjectToFinishLoading(TEST_PROJECT);
+    }
+  }
+
+  private RequestParametersSnippet createProjectRequestSnippet() {
+    return requestParameters(
+        parameterWithName("projectId")
+            .description("project identifier"),
+        parameterWithName("file-id")
+            .description("identifier of the file that should be used to create project"),
+        parameterWithName("parser")
+            .description("class of the parser that should be used for parsing the file. Available options: "
+                + snippets.getParsers()),
+        parameterWithName("cache")
+            .description("should the data from external sources be cached after project was created")
+            .optional(),
+        parameterWithName("description")
+            .description("description of the project")
+            .optional(),
+        parameterWithName("notify-email")
+            .description("email address that should be when something change in the project")
+            .optional(),
+        parameterWithName("disease")
+            .description("disease associated with the project (final MESH id)")
+            .optional(),
+        parameterWithName("name")
+            .description("name of the project")
+            .optional(),
+        parameterWithName("organism")
+            .description("organism associated with the project (final TAXONOMY id)")
+            .optional(),
+        parameterWithName("sbgn")
+            .description("should the map be visualized in sbgn-like way")
+            .optional(),
+        parameterWithName("semantic-zooming-contains-multiple-overlays")
+            .description("display each semantic zoom level in separate overlay")
+            .optional(),
+        parameterWithName("version")
+            .description("version of the project")
+            .optional(),
+        parameterWithName("mapCanvasType")
+            .description("type of map canvas engine to be used when visualizing map. Available options: "
+                + snippets.getOptionsAsString(MapCanvasType.class))
+            .optional(),
+        parameterWithName("annotate")
+            .description("should the project be automatically annotated")
+            .optional(),
+        parameterWithName("verify-annotations")
+            .description("should the annotations be verified")
+            .optional(),
+        parameterWithName("zip-entries")
+            .description(
+                "array of parameters describing each file in the zipped input file, file-index is number starting from 0")
+            .optional()
+
+    )
+        .and(createArrayParameters("zip-entries[{number}][_filename]", "name of the file"))
+        .and(createArrayParameters("zip-entries[{number}][_type]",
+            "type of the file. Possible values: "
+                + snippets.getOptionsAsString(ZipEntryFileDeserializer.ZipEntryFileType.class)))
+        .and(createArrayParameters("zip-entries[{number}][_data][name]", "name of the map/name of the overlay"))
+        .and(createArrayParameters("zip-entries[{number}][_data][mapping]",
+            "for submaps - is this map a mapping file (true/false)"))
+        .and(createArrayParameters("zip-entries[{number}][_data][root]",
+            "for submaps - is this map a root map (true/false)"))
+        .and(createArrayParameters("zip-entries[{number}][_data][type][id]",
+            "for submaps defines type of the connection. Possible values: "
+                + snippets.getOptionsAsString(SubmodelType.class)))
+        .and(createArrayParameters("zip-entries[{number}][_data][description]",
+            "for overlays - description of the overlay"));
+  }
+
+  private List<ParameterDescriptor> createArrayParameters(final String name, final String description) {
+    List<ParameterDescriptor> result = new ArrayList<>();
+    result.add(parameterWithName(name).description(description).optional());
+    for (int i = 0; i < 10; i++) {
+      result.add(parameterWithName(name.replace("{number}", i + "")).description(description).optional().ignored());
+    }
+    return result;
+  }
+
+}
diff --git a/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTest.java
index 05f0ec5ac43031ac89950ed861cc0504258f7d0f..8d65f84bbb5314b557a0a9e6f00188ca66b9b5ab 100644
--- a/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTest.java
@@ -2,6 +2,7 @@ package lcsb.mapviewer.web;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
@@ -14,16 +15,17 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.requestF
 import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
 import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
 import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
-import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
 import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.message.BasicNameValuePair;
@@ -37,9 +39,7 @@ import org.springframework.http.MediaType;
 import org.springframework.mock.web.MockHttpSession;
 import org.springframework.restdocs.payload.FieldDescriptor;
 import org.springframework.restdocs.payload.JsonFieldType;
-import org.springframework.restdocs.request.ParameterDescriptor;
 import org.springframework.restdocs.request.PathParametersSnippet;
-import org.springframework.restdocs.request.RequestParametersSnippet;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 import org.springframework.test.web.servlet.RequestBuilder;
 
@@ -47,7 +47,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.gson.JsonParser;
 
-import lcsb.mapviewer.converter.zip.ZipEntryFileDeserializer;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.ProjectStatus;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
@@ -55,7 +54,6 @@ import lcsb.mapviewer.model.graphics.MapCanvasType;
 import lcsb.mapviewer.model.map.MiriamType;
 import lcsb.mapviewer.model.map.layout.ProjectBackground;
 import lcsb.mapviewer.model.map.layout.ProjectBackgroundStatus;
-import lcsb.mapviewer.model.map.model.SubmodelType;
 import lcsb.mapviewer.model.security.Privilege;
 import lcsb.mapviewer.model.security.PrivilegeType;
 import lcsb.mapviewer.model.user.ConfigurationElementType;
@@ -117,6 +115,11 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
     MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD);
     RequestBuilder request = get("/api/projects/")
         .session(session);
+
+    Project project = projectService.getProjectByProjectId(BUILT_IN_PROJECT);
+    project.setDirectory(project.getDirectory().replaceAll("[a-z]", "0"));
+    projectService.updateProject(project);
+
     String response = mockMvc.perform(request)
         .andExpect(status().is2xxSuccessful())
         .andDo(document("projects/project_data/list",
@@ -170,6 +173,29 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
     assertEquals("curator should see only limited list of projects", 1, projects);
   }
 
+  @Test
+  public void testGetLimitedProjectsAsGuest() throws Exception {
+    Project project2 = new Project(TEST_PROJECT_2);
+    project2.setOwner(userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN));
+    projectService.add(project2);
+
+    RequestBuilder request = get("/api/projects/");
+
+    String response = mockMvc.perform(request)
+        .andDo(document("projects/project_data/list_guest",
+            responseFields(
+                subsectionWithPath("[]")
+                    .description("list of projects").type(JsonFieldType.ARRAY))))
+        .andExpect(status().is2xxSuccessful())
+        .andReturn().getResponse().getContentAsString();
+
+    int projects = new JsonParser()
+        .parse(response)
+        .getAsJsonArray().size();
+
+    assertEquals("guest should see only limited list of projects", 1, projects);
+  }
+
   @Test
   public void testUserPrivilegesChangeDuringActiveSession() throws Exception {
     MockHttpSession session = createSession(CURATOR_LOGIN, CURATOR_PASSWORD);
@@ -208,7 +234,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
                     .description("log entry column that should be used for sorting (default: id)").optional(),
                 parameterWithName("sortOrder").description("log entry sort order (asc, desc)").optional(),
                 parameterWithName("level").description("level of log entry (warning, error)").optional(),
-                parameterWithName("length").description("number of log entres we want to obtain").optional(),
+                parameterWithName("length").description("number of log entries we want to obtain").optional(),
                 parameterWithName("search").description("search query used for filtering").optional()),
             projectPathParameters(),
             responseFields(
@@ -576,232 +602,6 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
     mockMvc.perform(request).andExpect(status().isBadRequest());
   }
 
-  @Test
-  public void addProjectAsCurator() throws Exception {
-    User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
-    try {
-      UploadedFileEntry fileEntry = createFile(
-          new String(Files.readAllBytes(Paths.get("./src/test/resources/generic.xml")), "UTF-8"),
-          admin);
-
-      String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
-          new BasicNameValuePair("projectId", TEST_PROJECT),
-          new BasicNameValuePair("name", "New Disease Map"),
-          new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
-          new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
-          new BasicNameValuePair("cache", "false"),
-          new BasicNameValuePair("description", "this is my awesome project"),
-          new BasicNameValuePair("notify-email", "notify.me@uni.lu"),
-          new BasicNameValuePair("disease", "D010300"),
-          new BasicNameValuePair("organism", "9606"),
-          new BasicNameValuePair("sbgn", "false"),
-          new BasicNameValuePair("version", "0.0.1"),
-          new BasicNameValuePair("annotate", "false"),
-          new BasicNameValuePair("verify-annotations", "false"),
-          new BasicNameValuePair("parser", "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"))));
-
-      RequestBuilder request = post("/api/projects/{projectId}/", TEST_PROJECT)
-          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
-          .content(body)
-          .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
-
-      mockMvc.perform(request).andExpect(status().is2xxSuccessful())
-          .andDo(document("projects/project_data/create_simple",
-              projectPathParameters(),
-              createProjectRequestSnippet(),
-              snippets.getProjectSnippet()));
-
-    } finally {
-      waitForProjectToFinishLoading(TEST_PROJECT);
-    }
-  }
-
-  @Test
-  public void addProjectWithEmptyZipEntries() throws Exception {
-    User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
-    try {
-      UploadedFileEntry fileEntry = createFile(
-          new String(Files.readAllBytes(Paths.get("./src/test/resources/generic.xml")), "UTF-8"),
-          admin);
-
-      String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
-          new BasicNameValuePair("projectId", TEST_PROJECT),
-          new BasicNameValuePair("name", "New Disease Map"),
-          new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
-          new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
-          new BasicNameValuePair("cache", "false"),
-          new BasicNameValuePair("description", "this is my awesome project"),
-          new BasicNameValuePair("notify-email", "notify.me@uni.lu"),
-          new BasicNameValuePair("disease", "D010300"),
-          new BasicNameValuePair("organism", "9606"),
-          new BasicNameValuePair("sbgn", "false"),
-          new BasicNameValuePair("version", "0.0.1"),
-          new BasicNameValuePair("annotate", "false"),
-          new BasicNameValuePair("verify-annotations", "false"),
-          new BasicNameValuePair("zip-entries", ""),
-          new BasicNameValuePair("parser", "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"))));
-
-      RequestBuilder request = post("/api/projects/{projectId}/", TEST_PROJECT)
-          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
-          .content(body)
-          .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
-
-      mockMvc.perform(request).andExpect(status().is2xxSuccessful())
-          .andDo(document("projects/project_data/create_simple",
-              projectPathParameters(),
-              createProjectRequestSnippet(),
-              snippets.getProjectSnippet()));
-
-    } finally {
-      waitForProjectToFinishLoading(TEST_PROJECT);
-    }
-  }
-
-  @Test
-  public void addComplexProjectAsCurator() throws Exception {
-    User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
-    try {
-      UploadedFileEntry fileEntry = createFile(
-          Files.readAllBytes(Paths.get("./src/test/resources/complex_model_with_submaps.zip")), admin);
-
-      String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
-          new BasicNameValuePair("projectId", TEST_PROJECT),
-          new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
-          new BasicNameValuePair("name", "Project name"),
-          new BasicNameValuePair("version", "0.0.1"),
-          new BasicNameValuePair("notify-email", "minerva@uni.lu"),
-          new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
-          new BasicNameValuePair("parser",
-              "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"),
-
-          new BasicNameValuePair("zip-entries[0][_type]", "MAP"),
-          new BasicNameValuePair("zip-entries[0][_filename]", "main.xml"),
-          new BasicNameValuePair("zip-entries[0][_data][root]", "true"),
-          new BasicNameValuePair("zip-entries[0][_data][name]", "main"),
-          new BasicNameValuePair("zip-entries[0][_data][type][id]", "UNKNOWN"),
-
-          new BasicNameValuePair("zip-entries[1][_type]", "MAP"),
-          new BasicNameValuePair("zip-entries[1][_filename]", "submaps/mapping.xml"),
-          new BasicNameValuePair("zip-entries[1][_data][root]", "false"),
-          new BasicNameValuePair("zip-entries[1][_data][name]", "mapping"),
-          new BasicNameValuePair("zip-entries[1][_data][type][id]", "UNKNOWN"),
-
-          new BasicNameValuePair("zip-entries[2][_type]", "MAP"),
-          new BasicNameValuePair("zip-entries[2][_filename]", "submaps/s1.xml"),
-          new BasicNameValuePair("zip-entries[2][_data][root]", "false"),
-          new BasicNameValuePair("zip-entries[2][_data][name]", "s1"),
-          new BasicNameValuePair("zip-entries[2][_data][type][id]", "UNKNOWN"),
-
-          new BasicNameValuePair("zip-entries[3][_type]", "MAP"),
-          new BasicNameValuePair("zip-entries[3][_filename]", "submaps/s2.xml"),
-          new BasicNameValuePair("zip-entries[3][_data][root]", "false"),
-          new BasicNameValuePair("zip-entries[3][_data][name]", "s2"),
-          new BasicNameValuePair("zip-entries[3][_data][type][id]", "UNKNOWN"),
-
-          new BasicNameValuePair("zip-entries[4][_type]", "MAP"),
-          new BasicNameValuePair("zip-entries[4][_filename]", "submaps/s3.xml"),
-          new BasicNameValuePair("zip-entries[4][_data][root]", "false"),
-          new BasicNameValuePair("zip-entries[4][_data][name]", "s3"),
-          new BasicNameValuePair("zip-entries[4][_data][type][id]", "UNKNOWN")
-
-      )));
-
-      RequestBuilder request = post("/api/projects/{projectId}/", TEST_PROJECT)
-          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
-          .content(body)
-          .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
-
-      mockMvc.perform(request).andExpect(status().is2xxSuccessful())
-          .andDo(document("projects/project_data/create_zip",
-              projectPathParameters(),
-              createProjectRequestSnippet(),
-
-              snippets.getProjectSnippet()));
-
-    } finally {
-      waitForProjectToFinishLoading(TEST_PROJECT);
-      Project project = projectService.getProjectByProjectId(TEST_PROJECT);
-      assertEquals(ProjectStatus.DONE, project.getStatus());
-    }
-  }
-
-  private RequestParametersSnippet createProjectRequestSnippet() {
-    return requestParameters(
-        parameterWithName("projectId")
-            .description("project identifier"),
-        parameterWithName("file-id")
-            .description("identifier of the file that should be used to create project"),
-        parameterWithName("parser")
-            .description("class of the parser that should be used for parsing the file. Available options: "
-                + snippets.getParsers()),
-        parameterWithName("cache")
-            .description("should the data from external sources be cached after project was created")
-            .optional(),
-        parameterWithName("description")
-            .description("description of the project")
-            .optional(),
-        parameterWithName("notify-email")
-            .description("email address that should be when something change in the project")
-            .optional(),
-        parameterWithName("disease")
-            .description("disease associated with the project (final MESH id)")
-            .optional(),
-        parameterWithName("name")
-            .description("name of the project")
-            .optional(),
-        parameterWithName("organism")
-            .description("organism associated with the project (final TAXONOMY id)")
-            .optional(),
-        parameterWithName("sbgn")
-            .description("should the map be visualized in sbgn-like way")
-            .optional(),
-        parameterWithName("semantic-zoom")
-            .description("should custom semantic zooming be enabled")
-            .optional(),
-        parameterWithName("version")
-            .description("version of the project")
-            .optional(),
-        parameterWithName("mapCanvasType")
-            .description("type of map canvas engine to be used when visualizing map. Available options: "
-                + snippets.getOptionsAsString(MapCanvasType.class))
-            .optional(),
-        parameterWithName("annotate")
-            .description("should the project be automatically annotated")
-            .optional(),
-        parameterWithName("verify-annotations")
-            .description("should the annotations be verified")
-            .optional(),
-        parameterWithName("zip-entries")
-            .description(
-                "array of parameters describing each file in the zipped input file, file-index is number starting from 0")
-            .optional()
-
-    )
-        .and(createArrayParameters("zip-entries[{number}][_filename]", "name of the file"))
-        .and(createArrayParameters("zip-entries[{number}][_type]",
-            "type of the file. Possible values: "
-                + snippets.getOptionsAsString(ZipEntryFileDeserializer.ZipEntryFileType.class)))
-        .and(createArrayParameters("zip-entries[{number}][_data][name]", "name of the map/name of the overlay"))
-        .and(createArrayParameters("zip-entries[{number}][_data][mapping]",
-            "for submaps - is this map a mapping file (true/false)"))
-        .and(createArrayParameters("zip-entries[{number}][_data][root]",
-            "for submaps - is this map a root map (true/false)"))
-        .and(createArrayParameters("zip-entries[{number}][_data][type][id]",
-            "for submaps defines type of the connection. Possible values: "
-                + snippets.getOptionsAsString(SubmodelType.class)))
-        .and(createArrayParameters("zip-entries[{number}][_data][description]",
-            "for overlays - description of the overlay"));
-  }
-
-  private List<ParameterDescriptor> createArrayParameters(final String name, final String description) {
-    List<ParameterDescriptor> result = new ArrayList<>();
-    result.add(parameterWithName(name).description(description).optional());
-    for (int i = 0; i < 10; i++) {
-      result.add(parameterWithName(name.replace("{number}", i + "")).description(description).optional().ignored());
-    }
-    return result;
-  }
-
   @Test
   public void addInvalidProject() throws Exception {
     User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
@@ -899,34 +699,9 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
   public void removeProjectWithUsedFile() throws Exception {
     User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
     try {
-      UploadedFileEntry fileEntry = createFile(
-          new String(Files.readAllBytes(Paths.get("./src/test/resources/generic.xml")), "UTF-8"),
-          admin);
-
-      String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
-          new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
-          new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
-          new BasicNameValuePair("name", "Project name"),
-          new BasicNameValuePair("version", "0.0.1"),
-          new BasicNameValuePair("notify-email", "minerva@uni.lu"),
-          new BasicNameValuePair("parser",
-              "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"))));
+      createFullProject(admin);
 
-      RequestBuilder request = post("/api/projects/" + TEST_PROJECT)
-          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
-          .content(body)
-          .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
-      mockMvc.perform(request).andExpect(status().is2xxSuccessful());
-
-      request = post("/api/projects/" + TEST_PROJECT_2)
-          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
-          .content(body)
-          .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
-      mockMvc.perform(request).andExpect(status().is2xxSuccessful());
-
-      waitForProjectToFinishLoading(TEST_PROJECT_2);
-
-      request = delete("/api/projects/{projectId}/", TEST_PROJECT_2)
+      RequestBuilder request = delete("/api/projects/{projectId}/", TEST_PROJECT_2)
           .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
 
       mockMvc.perform(request).andExpect(status().is2xxSuccessful())
@@ -939,6 +714,40 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
     }
   }
 
+  private void createFullProject(final User admin)
+      throws UnsupportedEncodingException, IOException, Exception, InterruptedException {
+    UploadedFileEntry fileEntry = createFile(
+        new String(Files.readAllBytes(Paths.get("./src/test/resources/generic.xml")), "UTF-8"),
+        admin);
+
+    String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
+        new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
+        new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
+        new BasicNameValuePair("name", "Project name"),
+        new BasicNameValuePair("version", "0.0.1"),
+        new BasicNameValuePair("notify-email", "minerva@uni.lu"),
+        new BasicNameValuePair("parser",
+            "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"))));
+
+    RequestBuilder request = post("/api/projects/" + TEST_PROJECT)
+        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .content(body)
+        .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
+    mockMvc.perform(request).andExpect(status().is2xxSuccessful());
+
+    request = post("/api/projects/" + TEST_PROJECT_2)
+        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .content(body)
+        .session(createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD));
+    mockMvc.perform(request).andExpect(status().is2xxSuccessful());
+
+    waitForProjectToFinishLoading(TEST_PROJECT_2);
+
+    Project project = projectService.getProjectByProjectId(TEST_PROJECT_2);
+    project.setDirectory(project.getDirectory().replaceAll("[a-z]", "0"));
+    projectService.updateProject(project);
+  }
+
   @Test
   public void addComplexProjectWithInvalidOverlayName() throws Exception {
     User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
@@ -1062,6 +871,29 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
             responseFields().andWithPrefix("[].", getBackgroundFields())));
   }
 
+  private List<FieldDescriptor> getUpdateBackgroundFields() {
+    return Arrays.asList(
+        fieldWithPath("id")
+            .type(JsonFieldType.NUMBER)
+            .description("identifier"),
+        fieldWithPath("name")
+            .type(JsonFieldType.STRING)
+            .description("name"),
+        fieldWithPath("description")
+            .type(JsonFieldType.STRING)
+            .description("description"),
+        fieldWithPath("creator")
+            .type(JsonFieldType.STRING)
+            .description("who created background"),
+        fieldWithPath("order")
+            .type(JsonFieldType.NUMBER)
+            .description("order used when listing all backgrounds"),
+        fieldWithPath("defaultOverlay")
+            .type(JsonFieldType.BOOLEAN)
+            .description(
+                "should the background be used as default (at most one per project should be marked with true)"));
+  }
+
   private List<FieldDescriptor> getBackgroundFields() {
     return Arrays.asList(
         fieldWithPath("id")
@@ -1128,6 +960,8 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
     Project project = createAndPersistProject(TEST_PROJECT);
     ProjectBackground background = new ProjectBackground("weird_title");
     background.setId(project.getProjectBackgrounds().get(0).getId());
+    background.setCreator(userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN));
+    background.setDescription("new description");
 
     ObjectMapper mapper = new ObjectMapper();
     mapper.addMixIn(ProjectBackground.class, ProjectBackgroundUpdateMixIn.class);
@@ -1142,6 +976,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
         .andExpect(status().is2xxSuccessful())
         .andDo(document("projects/project_backgrounds/update_background",
             backgroundPathParameters(),
+            requestFields(getUpdateBackgroundFields()),
             responseFields(getBackgroundFields())))
         .andReturn().getResponse().getContentAsString();
 
@@ -1194,10 +1029,6 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
     assertEquals(backgrounds.size() - 1, backgroundCount);
   }
 
-  private PathParametersSnippet projectPathParameters() {
-    return pathParameters(parameterWithName("projectId").description("project identifier"));
-  }
-
   private PathParametersSnippet backgroundPathParameters() {
     return projectPathParameters().and(parameterWithName("backgroundId").description("background identifier"));
   }
@@ -1446,4 +1277,56 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
         .andExpect(status().is2xxSuccessful());
   }
 
+  @Test
+  public void addComplexProjectWithGenomicLayout() throws Exception {
+    User admin = userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN);
+    MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD);
+
+    UploadedFileEntry fileEntry = createFile(
+        Files.readAllBytes(Paths.get("./src/test/resources/complex_model_with_genomic_layout.zip")), admin);
+    try {
+      String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
+          new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
+          new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
+          new BasicNameValuePair("parser", "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"),
+
+          new BasicNameValuePair("zip-entries[0][_type]", "MAP"),
+          new BasicNameValuePair("zip-entries[0][_filename]", "main.xml"),
+          new BasicNameValuePair("zip-entries[0][_data][root]", "true"),
+          new BasicNameValuePair("zip-entries[0][_data][name]", "s1"),
+          new BasicNameValuePair("zip-entries[0][_data][type][id]", "UNKNOWN"),
+          new BasicNameValuePair("zip-entries[0][_data][type][name]", "Unknown"),
+
+          new BasicNameValuePair("zip-entries[1][_type]", "OVERLAY"),
+          new BasicNameValuePair("zip-entries[1][_filename]", "layouts/goodSchema.txt"),
+          new BasicNameValuePair("zip-entries[1][_data][name]", "test-o")
+
+      )));
+
+      RequestBuilder request = post("/api/projects/" + TEST_PROJECT)
+          .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+          .content(body)
+          .session(session);
+
+      mockMvc.perform(request).andExpect(status().is2xxSuccessful());
+      waitForProjectToFinishLoading(TEST_PROJECT);
+
+      RequestBuilder overlayRequest = get("/api/projects/{projectId}/overlays/", TEST_PROJECT)
+          .session(session);
+
+      String json = mockMvc.perform(overlayRequest)
+          .andExpect(status().is2xxSuccessful())
+          .andReturn().getResponse().getContentAsString();
+      List<Map<String, Object>> overlays = objectMapper.readValue(json, new TypeReference<List<Map<String, Object>>>() {
+      });
+
+      logger.debug(json);
+
+      assertNotNull(overlays.get(0).get("genomeType"));
+      assertNotNull(overlays.get(0).get("genomeVersion"));
+    } finally {
+      waitForProjectToFinishLoading(TEST_PROJECT);
+    }
+  }
+
 }
diff --git a/web/src/test/java/lcsb/mapviewer/web/UserControllerAnonymousIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/UserControllerAnonymousIntegrationTest.java
index 2a18af22f3d8b678310c1f44ff1359d54ef846a0..26e391ceb1985edb6b4e40ba4c2b9f38f7d0987e 100644
--- a/web/src/test/java/lcsb/mapviewer/web/UserControllerAnonymousIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/UserControllerAnonymousIntegrationTest.java
@@ -15,6 +15,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
 
 import java.util.Map;
 
+import javax.servlet.http.Cookie;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -36,7 +38,6 @@ public class UserControllerAnonymousIntegrationTest extends ControllerIntegratio
   @Autowired
   private IUserService userService;
 
-
   @Before
   public void setup() {
   }
@@ -153,13 +154,13 @@ public class UserControllerAnonymousIntegrationTest extends ControllerIntegratio
     MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD);
 
     RequestBuilder request = post("/api/doLogout")
+        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+        .cookie(new Cookie(Configuration.AUTH_TOKEN, "xxxxxxxx"))
         .session(session);
 
     mockMvc.perform(request)
         .andDo(document("authentication/logout",
-            responseFields(
-                fieldWithPath("status")
-                    .description("status message"))))
+            responseFields(fieldWithPath("status").description("status message"))))
         .andExpect(status().is2xxSuccessful());
   }
 
@@ -173,7 +174,6 @@ public class UserControllerAnonymousIntegrationTest extends ControllerIntegratio
     Map<String, Object> result = objectMapper.readValue(content, new TypeReference<Map<String, Object>>() {
     });
 
-    logger.debug(result);
     assertNotNull(result.get("preferences"));
   }
 
diff --git a/web/src/test/java/lcsb/mapviewer/web/UserControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/UserControllerIntegrationTest.java
index ababc861cf25ad503a3ff5d7b263e74b10e776c4..c06163b510596263606000bb769b6100cb56cc9b 100644
--- a/web/src/test/java/lcsb/mapviewer/web/UserControllerIntegrationTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/UserControllerIntegrationTest.java
@@ -24,6 +24,7 @@ import java.util.Calendar;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
@@ -51,7 +52,6 @@ import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 
-import lcsb.mapviewer.annotation.services.ModelAnnotator;
 import lcsb.mapviewer.annotation.services.annotators.UniprotAnnotator;
 import lcsb.mapviewer.api.users.UserController;
 import lcsb.mapviewer.api.users.UserController.UserPrivilegesDTO;
@@ -92,7 +92,7 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
   private static final String TEST_USER_PASSWORD = "test_pass";
   private static final String TEST_USER_LOGIN = "test_user";
 
-  private static final String TEST_LOGIN = "xyz";
+  private static final String TEST_LOGIN = "test_login";
 
   private User user;
 
@@ -114,9 +114,6 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
   @Autowired
   private UserController userController;
 
-  @Autowired
-  private ModelAnnotator modelAnnotator;
-
   @Before
   public void setup() throws Exception {
     user = createUser(TEST_USER_LOGIN, TEST_USER_PASSWORD);
@@ -194,7 +191,8 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
     mockMvc.perform(request)
         .andExpect(status().is2xxSuccessful());
 
-    assertEquals("Privilege wasn't revoked", 0, userService.getUserByLogin(TEST_USER_LOGIN, true).getPrivileges().size());
+    assertEquals("Privilege wasn't revoked", 0,
+        userService.getUserByLogin(TEST_USER_LOGIN, true).getPrivileges().size());
   }
 
   @Test
@@ -420,8 +418,8 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
     MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD);
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
-        new BasicNameValuePair("name", "FirstName"),
-        new BasicNameValuePair("password", "FirstName"))));
+        new BasicNameValuePair("name", "Name"),
+        new BasicNameValuePair("password", "Password"))));
 
     RequestBuilder grantRequest = post("/api/users/{login}", TEST_LOGIN)
         .contentType(MediaType.APPLICATION_FORM_URLENCODED)
@@ -431,7 +429,7 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
     mockMvc.perform(grantRequest)
         .andDo(document("user/create_user",
             userPathParameters(),
-            requestParameters(getUserRequestFieldsWithoutLogin()),
+            requestParameters(addUserRequestFields()),
             responseFields(getUserResponseFields())))
         .andExpect(status().is2xxSuccessful());
 
@@ -465,7 +463,7 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("name", "FirstName"),
-        new BasicNameValuePair("password", "FirstName"),
+        new BasicNameValuePair("password", "UserPassword"),
         new BasicNameValuePair("defaultPrivileges", "true"))));
 
     RequestBuilder grantRequest = post("/api/users/" + TEST_LOGIN)
@@ -499,7 +497,7 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
 
     String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("name", "FirstName"),
-        new BasicNameValuePair("password", "FirstName"),
+        new BasicNameValuePair("password", "UserPassword"),
         new BasicNameValuePair("defaultPrivileges", "true"))));
 
     RequestBuilder grantRequest = post("/api/users/" + TEST_LOGIN)
@@ -693,15 +691,13 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
   @Test
   public void resetPassword() throws Exception {
     configureServerForResetPasswordRequest();
-
-    RequestBuilder request = post("/api/users/" + TEST_USER_LOGIN + ":requestResetPassword");
-
-    mockMvc.perform(request)
-        .andExpect(status().is2xxSuccessful());
-
     String newPassword = "pass2";
 
-    ResetPasswordToken token = userService.getPasswordTokens(TEST_USER_LOGIN).get(0);
+    Calendar expires = Calendar.getInstance();
+    expires.add(Calendar.DAY_OF_MONTH, 1);
+    ResetPasswordToken token = new ResetPasswordToken(user, UUID.randomUUID().toString().replaceAll("[a-z]", "0"),
+        expires);
+    userService.add(token);
 
     String content = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
         new BasicNameValuePair("token", token.getToken()),
@@ -719,7 +715,7 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
                     .description("new password"),
                 parameterWithName("token")
                     .optional()
-                    .description("reset poassowrd token obtained using email"))))
+                    .description("reset password token obtained using email"))))
         .andExpect(status().is2xxSuccessful());
 
     createSession(TEST_USER_LOGIN, newPassword);
@@ -808,7 +804,8 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
     user.setEmail("test@test.xyz");
     userService.updateUser(user);
 
-    configurationService.setConfigurationValue(ConfigurationElementType.MINERVA_ROOT, "https://minerva-dev.lcsb.uni.lu/minerva/");
+    configurationService.setConfigurationValue(ConfigurationElementType.MINERVA_ROOT,
+        "https://minerva-dev.lcsb.uni.lu/minerva/");
   }
 
   @Test
@@ -850,11 +847,11 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
             .optional()
             .type(JsonFieldType.STRING),
         fieldWithPath("connectedToLdap")
-            .description("is user account connected to ldap")
+            .description("is user account connected to LDAP")
             .optional()
             .type(JsonFieldType.BOOLEAN),
         fieldWithPath("ldapAccountAvailable")
-            .description("does is account exist in ldap")
+            .description("does the account exist in LDAP")
             .optional()
             .type(JsonFieldType.BOOLEAN),
         fieldWithPath("email")
@@ -918,6 +915,24 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
     return result;
   }
 
+  private List<ParameterDescriptor> addUserRequestFields() {
+    return Arrays.asList(
+        parameterWithName("name")
+            .optional()
+            .description("first name"),
+        parameterWithName("surname")
+            .optional()
+            .description("last name"),
+        parameterWithName("password")
+            .description("user password"),
+        parameterWithName("email")
+            .optional()
+            .description("email address"),
+        parameterWithName("defaultPrivileges")
+            .optional()
+            .description("should the default privileges be added to the user after user creation"));
+  }
+
   private List<ParameterDescriptor> getUserRequestFieldsWithoutLogin() {
     return Arrays.asList(
         parameterWithName("password")
@@ -925,10 +940,10 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
             .description("user password"),
         parameterWithName("connectedToLdap")
             .optional()
-            .description("is user account connected to ldap"),
+            .description("is user account connected to LDAP"),
         parameterWithName("ldapAccountAvailable")
             .optional()
-            .description("does is account exist in ldap"),
+            .description("does is account exist in LDAP"),
         parameterWithName("email")
             .optional()
             .description("email address"),
@@ -994,7 +1009,8 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
     uniprotAnnotator.addAnnotatorParameter(new AnnotatorOutputParameter(MiriamType.UNIPROT));
     uniprotAnnotator.addAnnotatorParameter(new AnnotatorOutputParameter(MiriamType.EC));
     uniprotAnnotator.addAnnotatorParameter(new AnnotatorOutputParameter(MiriamType.ENTREZ));
-    uniprotAnnotator.addAnnotatorParameter(new AnnotatorConfigParameter(AnnotatorParamDefinition.KEGG_ORGANISM_IDENTIFIER, "XXX"));
+    uniprotAnnotator
+        .addAnnotatorParameter(new AnnotatorConfigParameter(AnnotatorParamDefinition.KEGG_ORGANISM_IDENTIFIER, "XXX"));
     preferences.addClassAnnotator(new UserClassAnnotators(Gene.class, Arrays.asList(uniprotAnnotator)));
 
     RequestBuilder request = patch("/api/users/{login}:updatePreferences", TEST_USER_LOGIN)
@@ -1024,8 +1040,10 @@ public class UserControllerIntegrationTest extends ControllerIntegrationTest {
 
     UserAnnotationSchema preferences = new UserAnnotationSchema();
     UserPreferencesDTO data = new UserPreferencesDTO(preferences);
-    preferences.addClassRequiredAnnotations(new UserClassRequiredAnnotations(Protein.class, Arrays.asList(MiriamType.HGNC, MiriamType.HGNC_SYMBOL)));
-    preferences.addClassRequiredAnnotations(new UserClassRequiredAnnotations(SimpleMolecule.class, Arrays.asList(MiriamType.CHEBI)));
+    preferences.addClassRequiredAnnotations(
+        new UserClassRequiredAnnotations(Protein.class, Arrays.asList(MiriamType.HGNC, MiriamType.HGNC_SYMBOL)));
+    preferences.addClassRequiredAnnotations(
+        new UserClassRequiredAnnotations(SimpleMolecule.class, Arrays.asList(MiriamType.CHEBI)));
     preferences.getClassRequiredAnnotators().get(1).setRequireAtLeastOneAnnotation(false);
 
     RequestBuilder request = patch("/api/users/{login}:updatePreferences", TEST_USER_LOGIN)
diff --git a/web/src/test/java/lcsb/mapviewer/web/serialization/ProjectBackgroundUpdateMixIn.java b/web/src/test/java/lcsb/mapviewer/web/serialization/ProjectBackgroundUpdateMixIn.java
index 51c649c3405edfb4d9b06ced01b7c2263ebad2e2..dcab549d802fefad027dd01096292dcaeb3b8228 100644
--- a/web/src/test/java/lcsb/mapviewer/web/serialization/ProjectBackgroundUpdateMixIn.java
+++ b/web/src/test/java/lcsb/mapviewer/web/serialization/ProjectBackgroundUpdateMixIn.java
@@ -3,10 +3,13 @@ package lcsb.mapviewer.web.serialization;
 import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.map.layout.ProjectBackgroundImageLayer;
 import lcsb.mapviewer.model.map.layout.ProjectBackgroundStatus;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.modelutils.serializer.model.user.UserAsLoginSerializer;
 
 public abstract class ProjectBackgroundUpdateMixIn {
   @JsonIgnore
@@ -26,7 +29,10 @@ public abstract class ProjectBackgroundUpdateMixIn {
 
   @JsonIgnore
   public abstract double getProgress();
-  
+
   @JsonIgnore
   public abstract List<ProjectBackgroundImageLayer> getProjectBackgroundImageLayer();
+
+  @JsonSerialize(using = UserAsLoginSerializer.class)
+  public abstract User getCreator();
 }
diff --git a/web/src/test/java/lcsb/mapviewer/web/utils/CommandFormatterWithReplacingPostFilenameHeader.java b/web/src/test/java/lcsb/mapviewer/web/utils/CommandFormatterWithReplacingPostFilenameHeader.java
index 608e42fdd17351e5089f551dc58d842d1564df91..b42b9465db3d4735d39ef7221928fbfc202ea16c 100644
--- a/web/src/test/java/lcsb/mapviewer/web/utils/CommandFormatterWithReplacingPostFilenameHeader.java
+++ b/web/src/test/java/lcsb/mapviewer/web/utils/CommandFormatterWithReplacingPostFilenameHeader.java
@@ -2,6 +2,8 @@ package lcsb.mapviewer.web.utils;
 
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.restdocs.cli.CommandFormatter;
 import org.springframework.util.CollectionUtils;
 
@@ -14,11 +16,20 @@ import lcsb.mapviewer.common.Configuration;
  * reference @filename. The filename is taken from header "post-filename" which
  * will be removed from the curl sample.
  * 
+ * <p>
+ * It is also a workaround the issue that restdocs ignores fact that curl by
+ * default uses application/x-www-form-urlencoded content-type if no content
+ * type is provided.
+ * </p>
+ * 
+ * 
  * @author Piotr Gawron
  *
  */
 public class CommandFormatterWithReplacingPostFilenameHeader implements CommandFormatter {
 
+  protected static Logger logger = LogManager.getLogger();
+
   private String separator;
 
   /**
@@ -41,14 +52,14 @@ public class CommandFormatterWithReplacingPostFilenameHeader implements CommandF
   @Override
   public String format(final List<String> elements) {
     if (CollectionUtils.isEmpty(elements)) {
-      return "";
-    }
-    String contentFileName = null;
-    for (final String element : elements) {
-      if (element.startsWith("-H 'post-filename:")) {
-        contentFileName = element.replace("-H 'post-filename: ", "").replace("'", "");
+      if (session) {
+        return String.format(this.separator) + "--cookie \"" + Configuration.AUTH_TOKEN + "=xxxxxxxx\"";
       }
+      return "";
     }
+    String contentFileName = getContentFileName(elements);
+    String contentType = getContentType(elements);
+
     if (session) {
       elements.add("--cookie \"" + Configuration.AUTH_TOKEN + "=xxxxxxxx\"");
     }
@@ -58,14 +69,42 @@ public class CommandFormatterWithReplacingPostFilenameHeader implements CommandF
       if (element.startsWith("-d") && contentFileName != null) {
         element = "--data-binary @" + contentFileName;
       }
-      if (!element.startsWith("-H 'post-filename:")) {
+      if (!element.startsWith("-H 'post-filename:")
+          && !element.toLowerCase().startsWith("-h 'content-type:")) {
         result.append(String.format(this.separator));
         result.append(element);
       }
     }
+    if (contentType != null && !contentType.isEmpty()) {
+      result.append(String.format(this.separator));
+      result.append("-H 'Content-Type: " + contentType + "'");
+    }
     return result.toString();
   }
 
+  public String getContentType(final List<String> elements) {
+    String contentType = "application/octet-stream";
+    for (String orgString : elements) {
+      String string = orgString.replaceAll("\\s+", "")
+          .replaceAll("'", "")
+          .replaceAll("\"", "");
+      if (string.toLowerCase().startsWith("-hcontent-type:")) {
+        return string.split(":")[1];
+      }
+    }
+    return contentType;
+  }
+
+  private String getContentFileName(final List<String> elements) {
+    String contentFileName = null;
+    for (final String element : elements) {
+      if (element.startsWith("-H 'post-filename:")) {
+        contentFileName = element.replace("-H 'post-filename: ", "").replace("'", "");
+      }
+    }
+    return contentFileName;
+  }
+
   public void setSessionAvailable(final boolean session) {
     this.session = session;
   }
diff --git a/web/src/test/java/lcsb/mapviewer/web/utils/CustomCurlRequestSnippet.java b/web/src/test/java/lcsb/mapviewer/web/utils/CustomCurlRequestSnippet.java
index 3c37f8e3e963d06d5720b3a02564f54c81df4a25..0766e3a0054f08696859796e94923fb65d6fa49d 100644
--- a/web/src/test/java/lcsb/mapviewer/web/utils/CustomCurlRequestSnippet.java
+++ b/web/src/test/java/lcsb/mapviewer/web/utils/CustomCurlRequestSnippet.java
@@ -2,6 +2,8 @@ package lcsb.mapviewer.web.utils;
 
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.restdocs.cli.CommandFormatter;
 import org.springframework.restdocs.cli.CurlRequestSnippet;
 import org.springframework.restdocs.operation.Operation;
@@ -17,6 +19,8 @@ import org.springframework.restdocs.operation.Operation;
  */
 public class CustomCurlRequestSnippet extends CurlRequestSnippet {
 
+  protected static Logger logger = LogManager.getLogger();
+
   private final CommandFormatter commandFormatter;
 
   public CustomCurlRequestSnippet(final CommandFormatter commandFormatter) {
@@ -35,11 +39,19 @@ public class CustomCurlRequestSnippet extends CurlRequestSnippet {
     boolean session = false;
     if (obj instanceof org.springframework.mock.web.MockHttpServletRequest) {
       session = (((org.springframework.mock.web.MockHttpServletRequest) obj).getSession() != null);
+      if (session) {
+        session = !((org.springframework.mock.web.MockHttpServletRequest) obj).getSession().isNew();
+      }
     }
     if (commandFormatter instanceof CommandFormatterWithReplacingPostFilenameHeader) {
       ((CommandFormatterWithReplacingPostFilenameHeader) commandFormatter).setSessionAvailable(session);
     }
-    return super.createModel(operation);
+    Map<String, Object> result = super.createModel(operation);
+
+    String options = (String) result.get("options");
+    // get rid of writeIncludeHeadersInOutputOption
+    result.put("options", options.replace("-i ", ""));
+    return result;
   }
 
 }
diff --git a/web/src/test/resources/complex_model_with_genomic_layout.zip b/web/src/test/resources/complex_model_with_genomic_layout.zip
new file mode 100644
index 0000000000000000000000000000000000000000..b8df8b8a9ac8bca2b9428088ad125f76fd83cc48
Binary files /dev/null and b/web/src/test/resources/complex_model_with_genomic_layout.zip differ